AdaPower Logged in as Guest
Ada Tools and Resources

Ada 95 Reference Manual
Ada Source Code Treasury
Bindings and Packages
Ada FAQ


Join >
Articles >
Ada FAQ >
Getting Started >
Home >
Books & Tutorials >
Source Treasury >
Packages for Reuse >
Latest Additions >
Ada Projects >
Press Releases >
Ada Audio / Video >
Home Pages >
Links >
Contact >
About >
Login >
Back
Passing a subroutine as a parameter to another subroutine (Roger Racine, Ludovic Brenta, Tom Moran)

How do I pass a subroutine as a parameter to another subroutine?

-------------------------------------------------------------------------------
Answer 1: (Roger Racine)
-------------------------------------------------------------------------------

With Ada95 it is quite straightforward (see section 3.10
of the Reference Manual).  You simply create an access type and use the
access type  as the parameter.

-------------------------------------------------------------------------------

with Text_Io; use Text_IO;
procedure Test_Proc_Access is
   type Proc_Access_T is access procedure (X : Integer);
   procedure My_Proc (X : Integer) is
   begin
      Put (Integer'Image(X));
   end My_Proc;

   procedure Call_It (Proc_Access : Proc_Access_T) is
   begin
      Proc_Access.all(5);
   end Call_It;

begin
   Call_It (My_Proc'Access);
end Test_Proc_Access;

-------------------------------------------------------------------------------
Answer 2: (Ludovic Brenta)
-------------------------------------------------------------------------------

Generics are usually preferred to access-to-subprograms because they
are safer since no null access value can ever exist.

-------------------------------------------------------------------------------

procedure Test is
   generic
      with procedure To_Be_Called (The_Parameter : in Whatever);
   procedure Generic_Proc;

   procedure Generic_Proc is
   begin
      To_Be_Called (The_Parameter => ...);
   end Generic_Proc;

   procedure First (The_Parameter : in Whatever) is separate;

   procedure Second is new Generic_Proc (To_Be_Called => First);
begin -- Test
   Second;
end Test;

-------------------------------------------------------------------------------
Answer 3: (Tom Moran)
-------------------------------------------------------------------------------

Use an abstract tagged type with a subprogram, creating a non-abstract type 
with the particular subprogram you want to pass.

-------------------------------------------------------------------------------

-- Here is an example using tagged types to pass a function
-- as a parameter to a procedure.  In this example, the passed
-- functions are f(x)=sin(x) and f(x)=a*x+b and the procedure prints
-- the integral from x=0.0 .. 1.0 of the function it is given.
-- tmoran@acm.org 11/11/04 for instructional purposes only

package Integrands is
  type Functions is abstract tagged null record;
  function F(Selector: Functions;
             X       : Float) return Float is abstract;
end Integrands;

with Integrands;
package Some_Functions is

  type Sin_Type is new Integrands.Functions with null record;
  function F(Selector: Sin_Type;
             X       : Float) return Float;
  -- f(x) = sin(x)

  type Ramp_Type is new Integrands.Functions with record
    A, B : Float;
  end record;
  function F(Selector: Ramp_Type;
             X       : Float) return Float;
  -- f(x) = a*x+b

end Some_Functions;

with Ada.Numerics.Elementary_Functions;
package body Some_Functions is

  function F(Selector: Sin_Type;
             X       : Float) return Float is
  -- f(x) = sin(x)
  begin
    return Ada.Numerics.Elementary_Functions.Sin(X);
  end F;

  function F(Selector: Ramp_Type;
             X       : Float) return Float is
  -- f(x) = a*x+b
  begin
    return Selector.A * X + Selector.B;
  end F;

end Some_Functions;

with Ada.Text_Io, Integrands, Some_Functions;
procedure Example is

  procedure Integrate(Selector: Integrands.Functions'Class) is
    Sum : Float := 0.0;
  begin
    for I in 1 .. 100 loop
      Sum := Sum + 0.01 * Integrands.F(Selector, Float(I) / 100.0);
    end loop;
    Ada.Text_Io.Put_Line(Float'Image(Sum));
  end Integrate;

  Do_Sin  : Some_Functions.Sin_Type;

  Do_Ramp : Some_Functions.Ramp_Type := (A => 1.0, B => 0.0);

begin
  Ada.Text_Io.Put("integrated sin=");
  Integrate(Do_Sin);
  Ada.Text_Io.Put("integrated ramp=");
  Integrate(Do_Ramp);
end Example;

-------------------------------------------------------------------------------


(c) 1998-2004 All Rights Reserved David Botton