[net.lang.ada] Procedures as arguments

lazear@MITRE.ARPA (Walt Lazear) (10/22/85)

This may seem a naive question, since at first look it seems impossible:
can I (in Ada) pass the name (address) of a procedure to another procedure
to be executed by that called procedure?  My goal is to have a general
procedure that will call the supplied procedure until certain well-defined
conditions occur, then return to the original caller.  It is trivial to do
in C, but I cannot find anything comparable in Ada.  Thanks for any help.

	Walt (Lazear at MITRE.ARPA)

prindle@NADC.ARPA (10/22/85)

This subject was discussed at quite some length over a year ago on this list
(you might hunt down the archives).  The gist of the discussion was that it
could be done by making the procedure that is to call another procedure 
generic, with an instantiation parameter to define the procedure to be called.
The top level calling procedure then instantiates the generic once for each
different procedure that the generic must call, then calls the proper
instantiated procedure at the proper time.  My opposition to this solution
was that if multiple procedures were to be called, multiple copies of the
generic differing only in the procedure called from within itself would be
produced.  The rebuttal to this argument was that any reasonable compiler
would handle such instantiations by simply passing a hidden argument to the
middle procedure which was the address of the final procedure to be called 
(which, of course, is what everyone wanted to do in the first place, but
couldn't figure out how to).  Now the only problem is "where is this
*reasonable* compiler?".  The ALS compiler openly admits that there is no
code sharing between instantiations of the same generic; sort of leavs the
question open, doesn't it!  Perhaps others can tell this list how their
"favorite" Ada compiler handles multiple instantiations of a generic where the
only generic parameters are functions/procedures to be called (i.e. is a
hidden parameter passed for each function, is the code fully duplicated, or
perhaps something even more exciting done?).
Frank Prindle
Prindle@NADC

Geoff_Mendal@UMICH-MTS.MAILNET (10/23/85)

>This may seem a naive question, since at first look it seems impossible:
>can I (in Ada) pass the name (address) of a procedure to another procedure
>to be executed by that called procedure?  My goal is to have a general
>procedure that will call the supplied procedure until certain well-defined
>conditions occur, then return to the original caller.  It is trivial to do
>in C, but I cannot find anything comparable in Ada.  Thanks for any help.

Perhaps a generic subprogram with a formal subprogram parameter will
accomplish what you want. Consider the following simple example:

  generic
    with procedure Supplied_Procedure;
  procedure General_Procedure;
  . . .
  procedure General_Procedure is
  begin
    -- perhaps do something here
    Supplied_Procedure;
    -- perhaps do something here
  end General_Procedure;

All you need to do is instantiate the General_Procedure with the name of
a "supplied" procedure which you wish the General_Procedure to call. For
example, the following instantiation of General_Procedure will cause
"Hello" to be printed by a "supplied" procedure.

  with General_Procedure,
       Text_Io;
  procedure Main is
    procedure Print_Hello is
    begin
      Text_Io.Put_Line("Hello");
    end Print_Hello;

    procedure My_General_Procedure is new General_Procedure(Print_Hello);
  begin
    My_General_Procedure;
  end Main;

For simplicity, the above example assumes neither General_Procedure nor its
formal subprogram parameter pass any parameters. Passing parameters can also
be done, but the parameters of a generic formal subprogram must match those
of the actual subprogram. Hence, one can only use the above method to "pass"
subprograms that match the generic formal subprogram's parameter profile.

If generics don't do what you want, there might be another way, using
address clauses. I DO NOT ADVOCATE THIS METHOD. In fact, the ARM states that
doing so makes a program erroneous [ARM 13.5(8)]. Address clauses need not
even be implemented. With this in mind, consider the following:

  with system;
  procedure General_Procedure(Some_Procedure_Address : in System.Address) is
    procedure Supplied_Procedure;
    for Supplied_Procedure use at Some_Procedure_Address;
  begin
    -- perhaps do something here
    Supplied_Procedure;
    -- perhaps do something here
  end General_Procedure;
  . . .
  with General_Procedure,
       Text_Io;
  procedure Main is
    procedure Print_Hello is
    begin
      Text_Io.Put_Line("Hello");
    end Print_Hello;
  begin
    General_Procedure(Print_Hello'Address);
  end Main;

I doubt that this method would ever work in practice. I have yet to find an
implementation that will even compile/execute this second (erroneous) method
without blowing up (maybe that's an omen).

Geoff Mendal, Stanford U.

Berlen_Oronzo@QZCOM.MAILNET (10/25/85)

No you cannot pass any subprogram as a parameter using ADA.
It is due to another approach respect 'C' Programming Language.
One of ADA goals is to have a reliable and readable too
to develop programs , then it is impossible to do
                     Berlen Oronzo
                      CSATA Italy

jbn@wdl1.UUCP (10/26/85)

     The Verdix Ada compiler (5.0 Beta, SUN) allows sharing of generic
package bodies, but only if the generic parameters are restricted to
enumeration tpes, integer types, and floating types, and the
pragma SHARE_BODY is used.  But it doesn't work for generics with procedure
parameters.
     Considering that procedure parameters with full type checking are
provided for in the ISO Pascal standard (although not in Jensen and Wirth)
it's suprising that this was left out of Ada.

					John Nagle

macrakis@HARVARD.HARVARD.EDU (Stavros Macrakis) (10/28/85)

> >can I...pass the name (address) of a procedure to another procedure...?
> >[I want to] call the supplied procedure until certain well-defined
> >conditions occur....
> Perhaps a generic subprogram with a formal subprogram parameter ...

Yes, a generic procedure appears to be exactly what is needed here.

> If generics don't do what you want, there might be another way, using
> address clauses. I DO NOT ADVOCATE THIS METHOD. In fact, the ARM states
> that doing so makes a program erroneous [ARM 13.5(8)]. ...
>   procedure General_Procedure(Some_Procedure_Address : in System.Address) is
>     procedure Supplied_Procedure;
>     for Supplied_Procedure use at Some_Procedure_Address;
>   begin  ...
> I doubt that this method would ever work in practice. I have yet to find an
> implementation that will even compile/execute this second (erroneous) method
> without blowing up (maybe that's an omen).

Actually, this appears to be illegal: `For each subprogram declaration,
there must be a corresponding body (except for a subprogram written in
another language, as explained in section 13.9).' [RM 6.3/3]  Note that an
explicit reference is made to chapter 13 for the pragma Interface case,
but not for address clauses.  A problem with the wording of 13.5 is that
it says `An address clause specifies a required address in storage for an
entity.'  I suspect this is intended to mean `where an entity is to be
placed' rather than `where an entity should be considered to be'.


	-s