[net.lang.ada] Procedure Parameters

Robert.Firth@BD.SEI.CMU.EDU (06/11/86)

Recent posts have raised the issue of procedures
as parameters to other procedures.

First, this does not impair compile-time type
checking.  Parametric procedures cannot be type
checked in Algol-60 or Pascal because the language
does not require that their own parameters be
speciofied.  Naturally, if you don't specify the
formals, you can't check the actuals when the
parametric procedure is called, and I really cannot
understand why it needs 30 pages of formalism to
establish that.

However, this can be fixed simply by changing the
language to require full specification of parametric
procedures.  I did that when I wrote an Algol-60
compiler, and it gave no trouble.  In a language
such as Algol-68 or RTL/2 the task is harder, since
it is possible to define reflexive types, such as
a procedure that takes as a parameter another procedure
of its own type, or a STRUCT that contains a REF
to its own type.  In these cases, the type checking
algorithm is recursive, and to avoid infinite regress
must check for reflexive references; the usual way to
do this is by an Ariadne thread.

Secondly, adding parametric procedures, or even procedure
variables, does not greatly increase the complexity of
a language.  The implementation must construct a runtime
value that designates a procedure; this usually consists
of a component that points to the code and another that
identifies the execution environment (eg the end of a
static chain).  This latter component can be avoided if
one restricts the values of procedure variables to
outer-level procedures, as Modula-2 does, but in my
opinion the loss to the user far outweighs the gain to
the implementor.

Procedure variables can create a loophole in the scoping
structure in the same way that reference variables can:
it is possible to assign to a variable of greater extent
a value of smaller extent, and hence access via the
variable an object that no longer exists.  There is no
good way reliably to guard against this at compile time,
for which reason some people dislike procedure and
reference variables.  Algol-68 has this problem; Ada
avoids it by not permitting a pointer to a local variable.
Of course, the problem does not arise if parametric
procedures are allowed, but procedure variables aren't.

Finally, procedure variables in Ada.  They aren't there,
and I miss them.  There are three ways of coding around the
problem, but it must be admitted that they are bad ways,
and not a sensible substitute for the real thing.

(a) use tasks.  The English idiom to describe this is
    "too clever by half"

(b) use an enumeration type and a CASE statement as a
    dispatch list.  This fails because it requires the
    "actuals" to be known when the procedure with the
    "formal" is written, which (again in my opinion)
    is an unacceptable feature.

(c) cheat by passing 'ADDRESS of the actual and writing a
    magic CALL procedure.  You need a different CALL for
    each signature, to get the types right, and you lose
    the type checking.  Moreover, you probably can't get
    hold of the environment of the actual and so can pass
    only outer-level procedures with any chance of it working.

A fourth solution is to use generics and hope that the
implementation will indeed share code.

Why are procedure variables or parameters missing?  They
are forbidden by the Steelman requirement.  Now, in some
cases Ada diverges from the requirement (eg in providing
approximate fixed-point).  But the original type model
was designed without procedures as first-class objects, and
to change that would have been so great an upheaval that it
never seemed feasible.  Some of us urged it nevertheless,
especially after tasks were made (almost) first-class
objects.

But why was the requirement written that way?  The hidden
reason is that it was believed that programs in the
resulting language would be easier mechanically to verify,
if procedures did not have execution-time variability.
I happen to think this a bad reason, because I believe our
program verification techniques are so inadequate that, if we
restricted ourselves to things we could verify, we would be
able to write very little useful code.  There are few cases
where parametric procedures are required, but in those cases,
they are indispendsible, and the language is poorer without
them.

Yes, an issue for the 1988 revision.

Robert Firth