Gem #24: Null Considered Harmful (Part 2—Efficiency)

by Bob Duff—AdaCore

Let's get started…

In last week's gem, we talked about the documentation advantages of using "not null". Here's another example, first with null:

   <b>procedure</b> Iterate
     (T : Table; 
      Action : <b>access</b> <b>procedure</b> (X : <b>not</b> <b>null</b> Ref_Element)
                                      := <b>null</b>);
   <i>--  If Action is null, do nothing.</i>

...and without null:

   <b>procedure</b> Do_Nothing (X : <b>not</b> <b>null</b> Ref_Element) <b>is</b> <b>null</b>;
   <b>procedure</b> Iterate
     (T : Table; 
      Action : <b>not</b> <b>null</b> <b>access</b> <b>procedure</b> (X : <b>not</b> <b>null</b> Ref_Element)
                                      := Do_Nothing'<b>Access</b>);

I much prefer the style of the second Iterate.

The "not null access procedure" is quite a mouthful, but it's worthwhile, and anyway, the compatibility requirement for Ada 2005 requires that the "not null" be explicit, rather than the other way around.

Another advantage of "not null" over comments is for efficiency. For example:

   <b>procedure</b> P (X : <b>not</b> <b>null</b> Ref_Element) <b>is</b>
   <b>begin</b>
      X.<b>all</b>.Component := X.<b>all</b>.Component + 1;
   <b>end</b> P;
   <b>procedure</b> Q (X : <b>not</b> <b>null</b> Ref_Element) <b>is</b>
   <b>begin</b>
      <b>while</b> ... <b>loop</b>
         P (X);
      <b>end</b> <b>loop</b>;
   <b>end</b> Q;
   <b>procedure</b> R <b>is</b>
   <b>begin</b>
      Q (An_Element'<b>Access</b>);
   <b>end</b> R;

Without "not null", the generated code for P will do a check that X /= null, which may be costly on some systems. P is called in a loop, so this check will likely occur many times. With "not null", the check is pushed to the call site. Pushing checks to the call site is usually beneficial because (1) the check might be hoisted out of a loop by the optimizer, or (2) the check might be eliminated altogether, as in the example above, where the compiler knows that An_Element'Access cannot be null.

This is analogous to the situation in Ada 95 with other run-time checks, such as array bounds checks:

   <b>type</b> My_Index <b>is</b> <b>range</b> 1..10;
   <b>type</b> My_Array <b>is</b> <b>array</b> (My_Index) <b>of</b> Integer;
   <b>procedure</b> Process_Array (X : <b>in</b> <b>out</b> My_Array; Index : My_Index);

If "X (Index)" occurs inside Process_Array, there is no need to check that Index is in range, because the check is pushed to the caller.

Related Source Code

Ada Gems example files are distributed by AdaCore and may be used or modified for any purpose without restrictions.

gem_24.ada


Last Updated: 10/26/2017
Posted on: 1/28/2008