[comp.sys.mac.programmer] Variable procedures in Pascal

ralphm@elaine19.stanford.edu (Ralph Melton) (11/23/90)

I am using Think Pascal 3.01, and I really want to be able to declare
procedural variables.  I am writing a code resource for that calls one
procedure from another procedure many, many times.  However, the behavior
of this procedure depends on whether Color Quickdraw is available.
Currently, this looks like this:

{A1 is the procedure executed with ColorQD; A2 is the one executed without
ColorQD}

Procedure A;
begin
  if Color_QuickDraw_Is_Available then
    do A1
  else do A2
end;

Procedure B;
begin
  {lots of calls to procedure A}
end;

I would like to avoid repeating the check for Color Quickdraw by writing
something like this:

Procedure B;
var A : procedure;
begin
  if Color_QuickDraw_is_available then
    A := A1
  else A := A2;
  {lots of calls to procedure A, which is the correct one of the subprocedures}
end

I believe that it is possible to do such things in C, and I know about
procedural parameters in Pascal.  I also know that I can pass some Toolbox
routines the address of a procedure.  Is there any way to do what I want
within THINK Pascal?

Ralph
--
Ralph Melton	The White Rabbit	ralphm@portia.stanford.edu

"When you hear of a storybook romance, you don't think of the storybook
as being _Alice in Wonderland_ . . ."

aries@rhi.hi.is (Reynir Hugason) (11/26/90)

As far as I can remember MPW (and Think) only have procedural parameters,
i.e. you can only pass a procedure (or a function) to another procedure.
No tricky procedural variables.

The way it works:

PROCEDURE MainWork(PROCEDURE WhoYouGonnaCall(param1: INTEGER; ...));
  BEGIN
    { Do some stuff here }

    WhoYouGonnaCall(passParam1, ...);

    { Do more stuff here }
  END;

PROCEDURE DrawingWithColorQD(param1: INTEGER; ...);
  BEGIN
    { what-ever } 
  END;

PROCEDURE DrawingWithVanillaQD(param1: INTEGER; ...);
  BEGIN
    { do something else }
  END;

BEGIN
  IF (hasCQD)
    THEN MainWork(DrawingWithColorQD)
    ELSE MainWork(DrawingWithVanillaQD);
END.

---

Well that's it basically ... don't see why you don't write a couple
classes and make you're life a lot easier ;-)

---
Mimir Reynisson
Software Island

lins@Apple.COM (Chuck Lins) (11/27/90)

In article <2434@krafla.rhi.hi.is> aries@rhi.hi.is (Reynir Hugason) writes:
>As far as I can remember MPW (and Think) only have procedural parameters,
>i.e. you can only pass a procedure (or a function) to another procedure.
>No tricky procedural variables.

If you want something whose syntax is similar to Pascal, you can use Modula-2
which has direct support for procedure variables (with static typing). Pascal
does not support procedure variables.

-- 
Chuck Lins               | "Is this the kind of work you'd like to do?"
Apple Computer, Inc.     | -- Front 242
20525 Mariani Avenue     | Internet:  lins@apple.com
Mail Stop 37-BD          | AppleLink: LINS@applelink.apple.com
Cupertino, CA 95014      | "Self-proclaimed Object Oberon Evangelist"
The intersection of Apple's ideas and my ideas yields the empty set.

nebel@wam.umd.edu (Chris D. Nebel) (12/01/90)

In article <46833@apple.Apple.COM> lins@Apple.COM (Chuck Lins) writes:
>In article <2434@krafla.rhi.hi.is> aries@rhi.hi.is (Reynir Hugason) writes:
>>As far as I can remember MPW (and Think) only have procedural parameters,
>>i.e. you can only pass a procedure (or a function) to another procedure.
>>No tricky procedural variables.

Actually, it can be done by exploiting MPW Pascal's INLINE construct. What
you do is something like this:

procedure OneWay(stuff: StuffType);
   ...

procedure AnotherWay(stuff: StuffType);
   ...

procedure DoStuff(stuff: StuffType; useProc: ProcPtr);
   INLINE {whatever the opcodes are for move.l (sp)+, A0; jmp (A0) }

var
   theProc: ProcPtr;

begin
   theProc := @OneWay;
   DoStuff(stuff, theProc); { does it OneWay }
   theProc := @AnotherWay;
   DoStuff(stuff, theProc); { does it AnotherWay }
end.

A couple of caveats here: one, OneWay, AnotherWay, &c must have the same
parameters.  (If you're into playing really funny games with your compiler's
brain, the only real requirement is that the parameters for each procedure
occupy the same amount of space on the stack.)  Also, they must be globally
scoped, same as procedures used for filterProcs.

How it works: what the DoStuff stub is doing is to take the last parameter
it was passed (the ProcPtr) and then jump to that address.  Note that this
won't necessarily work on any compiler other than MPW Pascal.  Different
compilers handle parameters in different ways.

If this doesn't make any sense to you, write me and I'll try to explain
further.


Chris Nebel
nebel@wam.umd.edu

tim@hoptoad.uucp (Tim Maroney) (12/01/90)

In article <1990Nov23.082345.12074@portia.Stanford.EDU>
ralphm@elaine19.stanford.edu (Ralph Melton) writes:
>I am using Think Pascal 3.01, and I really want to be able to declare
>procedural variables.
>
>I believe that it is possible to do such things in C, and I know about
>procedural parameters in Pascal.  I also know that I can pass some Toolbox
>routines the address of a procedure.  Is there any way to do what I want
>within THINK Pascal?

Sure, but you need a little inline assembler.  Declare the procedure
variables as type ProcPtr (for internal documentation purposes).
Then declare an inline routine that takes the parameters of the
routine you are calling, plus an extra routine that's the ProcPtr.
The inline assembler pops the routine address off the stack and
jsr's to it.  For example:

function CallWombatNipple (operator: longint; params: Handle;
			   routine: ProcPtr): Handle;
	inline
		$205F, $4E90;								{ MOVE.L (A7)+,A0; JSR (A0) }

This is a way to call a routine that is declared as:

function WombatNipple (operator: longint; params: Handle): Handle;
-- 
Tim Maroney, Mac Software Consultant, sun!hoptoad!tim, tim@toad.com

The fact is self-evident from the text and requires no supporting argument.