[comp.lang.pascal] Procedures or Functions as parameters

windley@iris.ucdavis.edu (Phil Windley) (06/03/88)

In article <213@lafcol.UUCP> pilgrimk@lafcol.UUCP (Pilgrim Kenwyn A) writes:
>Has anyone tried to pass procedures or functions as parameters within
>user written procedures? 

Yes, see my example below.

>                               For example, the write(ln) procedure can be
>used with functions
>
>            e.g. write(Centered(Message)) 
>                 -where Centered is a user-written function
>                  with Message as a parameter
>

I don't understand your example.  It seems that Centered(Message) will be
evaluated and the result sent to write(), no magic here.

From your first question I presume you want to do something like this:

------------ cut here --------------------------------


program sumtest(input, output);


function sum(function term(x: integer): integer;
             a: integer;
             function next(y: integer): integer;
             b: integer):integer;
   begin
   if (a > b) then
      sum := 0
   else
      sum := term(a) + sum(term, next(a), next, b);
   end;

function sumCubes(a: integer; b: integer): integer;

   function cube(x:integer):integer;
      begin
      cube := x * x * x;
      end;

   function onePlus(x: integer): integer;
      begin
      onePlus := x + 1
      end;

   begin
   sumCubes := sum(cube, a, onePlus, b);
   end;

begin
writeln(sumCubes(1,10));
end.

--------------- end of example -------------------

Note that sum() is a function that takes two functions as parameters.  We
can define sumCubes() using sum().  (I have an example using sum() to do
integration as well.)  This program compiles on Berkeley pascal and as far
as I know uses no non-standard Pascal constructs. 


Phil Windley                          |  windley@iris.ucdavis.edu
Robotics Research Lab                 |  ucbvax!ucdavis!iris!windley
University of California, Davis       |

abcscnuk@csuna.UUCP (News Manager) (06/08/88)

In article <2165@ucdavis.ucdavis.edu> windley@iris.UUCP (Phil Windley) writes:
>In article <213@lafcol.UUCP> pilgrimk@lafcol.UUCP (Pilgrim Kenwyn A) writes:
>>Has anyone tried to pass procedures or functions as parameters within
>>user written procedures? 
>
>Yes, see my example below.
>
>>                               For example, the write(ln) procedure can be
>>used with functions
>>
>>            e.g. write(Centered(Message)) 
>>                 -where Centered is a user-written function
>>                  with Message as a parameter
>>
>
>I don't understand your example.  It seems that Centered(Message) will be
>evaluated and the result sent to write(), no magic here.

To paraphrase the previous poster, "Centered(Message)" is an expression,
which is passed to "Centered."  This is different from passing a function
as a parameter.  The example passed the value returned from the function,
not the function itself.  The example given is effectively no different from:

var
    str : string;  (* assuming Turbo Pascal 4.0 *)

...
    str := Centered(Message);
    write(str);

>
>From your first question I presume you want to do something like this:

	(* example deleted *)
>--------------- end of example -------------------
>
>Note that sum() is a function that takes two functions as parameters.  We
>can define sumCubes() using sum().  (I have an example using sum() to do
>integration as well.)  This program compiles on Berkeley pascal and as far
>as I know uses no non-standard Pascal constructs. 
>
>
>Phil Windley                          |  windley@iris.ucdavis.edu
>Robotics Research Lab                 |  ucbvax!ucdavis!iris!windley
>University of California, Davis       |

If your compiler is a REAL pascal compiler, it would have this feature,
if it doesn't, well, I'd consider it to be Wirth-less :-) (sorry I
couldn't resist).  Putting all the joking aside, TP4 isn't all that bad,
except for a few features of standard not being implemented.  If you
look carefully at the manual for Turbo (Appendix B p 532) you'll see it
clearly stated that procedural or functional parameters are not allowed
in Turbo.

The only way I could suggest it would be done is to do something along
these lines:

     - Where you might use a procedure or function parameter (in a standard
       pascal program), do the following:

       procedure foo( function bar : integer);  (* standard *)

		| change to
		V

       procedure foo( bar : pointer );          (* turbo 4.0 *)

     - In the body of the procedure or function that uses a procedure or
       function parameter, you'll then have to make sure that all the
       necessary parameters are pushed on the stack before a doing a call
       (either near or far, depending on how you want it, but make sure that
       use the right one) to the passed routine (the pointer to the function or
       procedure) by using the "inline" directive.   I don't have the necessary
       code with me right now...  Make sure that you handle function calls
       and procedure calls appropriately, (I don't recall right off hand where
       the return value of a function is returned, so you'll have to find out
       yourself).  Since Turbo 4.0 allows inline macros, you could define one
       for doing a near or far call.   Also, if the passed function or procedure
       expects parameters, you have to PUSH the appropriate stuff onto the
       stack (by using inline's) before you perform a near or far call to it.

     - Pass the address of the procedure or functions using the '@'
       operator in the main program:

		  foo(@plbbt);

With this approach you could get procedural and functional parameters to
work in Turbo, but the only problem is that YOU have to make sure that
when you want to pass a function that you are passing one, and not a
procedure, and likewise for the other case, otherwise this would cause
some pretty strange things to happen.  If anybody knows of a better way,
(besides using a different compiler) let me know.

                //-n-\\				Naoto Kimura
        _____---=======---_____			(csun!csuna!abcscnuk)
    ====____\   /.. ..\   /____====
  //         ---\__O__/---         \\	Enterprise... Surrender or we'll
  \_\                             /_/	send back your *&^$% tribbles !!

maurice@xanth.cs.odu.edu (Dale Ross Maurice) (06/08/88)

In article <12387@cci632.UUCP>:
>would be necessary. the procedure "call" would be an assembly macro (inline)
>which T$ supports (about time!). Although I don't have specific code for
>"call", on an 80x86 it could be done with:
>			CALL DWORD PTR [BP+{offset of A on stack}]
>	This is off the top of my head, so don't pound on me if it is wrong.

The easy way is as such: (This assumes no passing of varibles of course)
Var
	ProcPtr : Pointer;
.
.
	ProcPtr := @ProcName;
	Inline($FF/$1E/ProcPtr);       { Call Far [ProcPtr] }
.
.

[Any responses to this will have to wait 3 weeks.  It's vacation time again!]
-- 
uslessnessuselessnessuselessnessuselessnessuselessnessuselessnessuselessnesusel
* Dale Ross Maurice                   UUCP: maurice@xanth.UUCP                e
* Old Dominion University               or: ...!uunet!xanth!maurice           s
s BIRTHRIGHT PARTY IN SUPPORT     New ARPA: maurice@cs.edu.odu                s
s    OF THE SPACE EFFORT          Old ARPA: maurice%xanth.UUCP@SUN.COM        n
enesselesussensselesussensselesussensselesussensselesussensselesussensselesusse

agollum@engr.uky.edu (Kenneth Herron) (06/10/88)

>>>Has anyone tried to pass procedures or functions as parameters within
>>>user written procedures? 
>If you
>look carefully at the manual for Turbo (Appendix B p 532) you'll see it
>clearly stated that procedural or functional parameters are not allowed
>in Turbo.

(Actually it's page 520)

Well, the database toolbox SORT unit manages it.  It's kinda tricky
though...let's see how well I can describe it without violating their
copyright on the source code :-)

1) Define your procedures/functions like this:

{$F+}  {this is required}
Procedure Foo;
begin
[...]
end; {foo}

Function Bar(var X, Y: byte): boolean;
begin
[...]
end; {bar}
{$F-}

2) Declare a pointer like this
   var
      GluePtr: Pointer;  { generic pointer type }

3) Declare a function or procedure like this, with GluePtr declared
   outside it:
 
{$F+}
procedure CallProc;
inline($FF/$1E/GluePtr);  {CALL DWORD PTR GluePtr}
 
function CallFunc(var x, y: byte):boolean;
inline($FF/$1E/GluePtr);  {CALL DWORD PTR GluePtr}
{$F-}

   Note the actual parameter list should exactly match the parameter
   list of the function/procedure pointed to by GluePtr.
   You'll need to declare a different CallProc (with different names,
   natch) for a procedure with a different paramater list.  Same for
   CallFunc.

4) Call the darn thing like this:

GluePtr := @Foo;   {Foo is a procedure with no arguments}
CallProc;          {Foo will be executed}

GluePtr := @Bar;   {Bar is a procedure with two byte args, boolean return}
if CallFunc(x,y) then...

For a more real-world example, check out the toolbox.

Kenneth Herron

conliffe@caen.engin.umich.edu (Darryl C. Conliffe) (06/12/88)

In article <2165@ucdavis.ucdavis.edu>, windley@iris.ucdavis.edu (Phil Windley) writes:
> 
> From your first question I presume you want to do something like this:
> 
>[ code deleted ]
> 
> 
> Note that sum() is a function that takes two functions as parameters.  We
> can define sumCubes() using sum().  (I have an example using sum() to do
> integration as well.)  This program compiles on Berkeley pascal and as far
> as I know uses no non-standard Pascal constructs. 
> 
> 
> Phil Windley                          |  windley@iris.ucdavis.edu
> Robotics Research Lab                 |  ucbvax!ucdavis!iris!windley
> University of California, Davis       |

Apollo Pascal also compiles and executes without special options.

-- 
___________________

 Darryl C. Conliffe  conliffe@caen.engin.umich.edu  (313) 721-6069
-------------------