[net.lang.ada] Two characteristic programming errors in Ada

cw@sftor.UUCP (C.S.Wetherell) (04/04/86)

While porting some programs from the Simtel20 archives to our new
compiler, I had some difficulty with one of them.  Upon investigation,
I discovered two subtle but characteristic misuses of Ada.  I am sure they
are quite common, so I will protect the author.

Consider the following procedure declaration (ignore its innards for 
the moment)

   procedure Does_A_Check(Formal : in out NATURAL);

and the skeletal calling routine

   with Does_A_Check;
   procedure Im_A_Caller is
      Actual : NATURAL;
   begin
      Does_A_Check(Actual);
   end;

When this pair was linked and executed, a constraint exception was raised at
the point of call.  [This happened to be particularly mystifying in the
ported program, because the program was carefully taking care of all
exceptions and I couldn't tell at first exactly what was causing the
program to fail. Some embedding of trace statements uncovered the 
difficulty after a bit.]  Of course, the reason the constraint error
was raised was that variable Actual in Im_A_Caller was not
initialized; there is no requirement that the initial value of
a variable be within its declared bounds (with exception of access
types, of course).  Since formal in-out parameters are checked
for constraints at procedure entry, a constraint error was raised.
I can only assume that the particular program had always been compiled
and executed on a system where the initial values were within bounds;
this is, of course, an example of a bug common to other languages as
well.

However, there is a second bug in the program.  Let us now
consider the body of Does_A_Check:

   procedure Does_A_Check(Formal : in out NATURAL) is
   begin
      Formal := 0;
      ...
      Something := ... Formal ...;
      ...
   end;

Notice that the first thing Does_A_Check executes is an initializing
assignment to Formal; the routine really doesn't care about the 
in-bound value of the actual argument at all.  In fact, the only
reason that Formal is declared "in out" is so that it can be used
on the right-hand side of some statements.  Now, the Ada rule is that
an "out" parameter cannot be so used; the parameter may have an
undefined value at some places of such usage and the rules about
no right-hand usage keep the compiler from having to do a flow
analysis to determine if a particular usage is after a definition.
Here, the programmer, to save declaring a local variable, just made
Formal "in out"; then it can be used on the right.  But the cost is
unexpected constraint errors or extra work for the caller; 
after all, the caller doesn't know (in theory) why the formal parameter
is "in out" and may have to go to considerable trouble to guarantee that
the actual argument has an acceptable value; this is disturbing when 
the formal doesn't really need the initial value.

The moral seems to be to use "in out" parameters only when the
called routine actually needs the initial value; otherwise, use
a paradigm like

	procedure Does_A_Check(Formal : out NATURAL) is
           Local : NATURAL;
        begin
           Local := 0; -- yes, this could be done in the declaration.
           ...
           Something := ... Local ...
           ...
           Formal := Local;
           return;
        end Does_A_Check;

Finally, I might note that this problem was uncovered partly because our
compiler temporarily is storing characters in 16-bits while a little
part of our code generator is undergoing additional education about
the differences between signed and unsigned bytes.  One version of the
problem was using characters instead of NATURAL's. If the Actual
from above had been an 8-bit character, it might have been automatically
truncated to within the constraints; as a 16-bit character, it was not.
There is no guarantee in Ada about the sizes of types beyond the rules
governing type declarations; this particular stretch of code was
mildly unrobust in the face of changing sizes

Charles Wetherell
AT&T Information Systems
Summit NJ

RCONN@SIMTEL20.ARPA (Rick Conn) (04/06/86)

Charles, thank you very much for your message ... I have placed it
in the repository under PD:<ADA.EDUCATION> as PNOTE1.DOC.  If you (or any
repository user) are interested in common programming errors, John
Goodenough sent out a message earlier pertaining to a study he had done.
This message is in PD:<ADA.EDUCATION> as PROGERRS.DOC.
	Rick
-------