[comp.lang.pascal] TP5.5: Can't store method in procedure variable

dslg0849@uxa.cso.uiuc.edu (Daniel S. Lewart) (12/03/90)

I am attempting to store an object's method in a procedure variable in TP5.5.
However, I get a compiler error in the assignment statement.  What am I doing
wrong?  Is there some way to do what I want to do?

Thanks in advance,

Daniel Lewart
d-lewart@uiuc.edu
-------------------------------------------------------------------------------
{$F+}
type
  ObjectType = object
    procedure Method;
  end;
var
  Obj: ObjectType;
  ProcVar: procedure;

procedure ObjectType.Method;  begin end;
procedure Proc;  begin end;

Begin
  ProcVar := Proc;        { This compiles }
  ProcVar := Obj.Method;  { This doesn't }
End.
-------------------------------------------------------------------------------
e:\> tpc test
Turbo Pascal Version 5.5  Copyright (c) 1983,89 Borland International
TEST.PAS(15): Error 143: Invalid procedure or function reference.
  ProcVar := Obj.Method;  { This doesn't }
                       ^
-------------------------------------------------------------------------------

decomyn@penguin.uss.tek.com (12/04/90)

In article <1990Dec3.061013.22258@ux1.cso.uiuc.edu> dslg0849@uxa.cso.uiuc.edu (Daniel S. Lewart) writes:
>I am attempting to store an object's method in a procedure variable in TP5.5.
>However, I get a compiler error in the assignment statement.  What am I doing
>wrong?  Is there some way to do what I want to do?
>-------------------------------------------------------------------------------
>{$F+}
>type
>  ObjectType = object
>    procedure Method;
>  end;
>var
>  Obj: ObjectType;
>  ProcVar: procedure;
>
>procedure ObjectType.Method;  begin end;
>procedure Proc;  begin end;
>
>Begin
>  ProcVar := Proc;        { This compiles }
>  ProcVar := Obj.Method;  { This doesn't }
>End.
>-------------------------------------------------------------------------------
>TEST.PAS(15): Error 143: Invalid procedure or function reference.

The problem is that you are thinking of an object's methods as procedures.
Technically, they are not procedures, and you can't treat them the same as
independent procedures in many ways... including, apparently, this one.

Unfortunately, I can't think of an immediate answer.  You might try 
ProcVar := @Obj.Method, but I doubt that it will work.  Also, take a 
peek at how the Procedure variables are stored.  You might be able to force
the correct calling address in by creating an absolute variable record at the
Procedure variable location, something like this:

type
  Testrec = Record
	segm : word;
	offs : word;
  End;

var
[...]
  ProcCall : Testrec absolute ProcVar;

Begin
  Testrec.segm:=Seg(Obj.Method);
  Testrec.offs:=Ofs(Obj.Method);
[...]
etcetera.  It may or may not work.  (Note: the correct order may be offset 
first: I haven't looked at any generated code with that in mind)

Good luck.

-------------------------------------------------------------------------------
Brendt Hess a.k.a.             | Disclaimer: Opinions?  I don't even work here!
Vergil William de Comyn a.k.a. |-----------------------------------------------
Payne Hirds                    |       Life is not a zero-sum game:
decomyn@penguin.uss.tek.com    |          don't treat it as such.

garlange@mentor.cc.purdue.edu (Mark Garlanger) (12/04/90)

In article <1990Dec3.061013.22258@ux1.cso.uiuc.edu> dslg0849@uxa.cso.uiuc.edu (Daniel S. Lewart) writes:
>I am attempting to store an object's method in a procedure variable in TP5.5.
>However, I get a compiler error in the assignment statement.  What am I doing
>wrong?  Is there some way to do what I want to do?
>
The question I have is WHY you would want to do this?  Methods are closely
tied to the data structure associated with it.  What would you want the
program to do with the method tries to access the data that the object has 
defined?   What you are trying to do would cause many ambiguities for the 
compiler.  I bet there is a way to solve your general problem by using
the object-oriented programming directly, such as using virtual methods.
I have done some work with objects and if you gave your general problem, I
may be able to offer some hints on how to do it.

				Mark

dslg0849@uxa.cso.uiuc.edu (Daniel S. Lewart) (12/05/90)

garlange@mentor.cc.purdue.edu (Mark Garlanger) writes:

> The question I have is WHY you would want to do this?  Methods are closely
> tied to the data structure associated with it.  What would you want the
> program to do with the method tries to access the data that the object has 
> defined?   What you are trying to do would cause many ambiguities for the 
> compiler.  I bet there is a way to solve your general problem by using
> the object-oriented programming directly, such as using virtual methods.
> I have done some work with objects and if you gave your general problem, I
> may be able to offer some hints on how to do it.

My intention is to use object methods in my menuing system.  For each entry in
a menu, there is a procedure which is executed when that entry is selected.
This works for ordinary procedures, but it won't even compile for object
methods.  The example I posted was constructed to illustrate my problem as
simply as possible.

I don't see how there would be any compiler ambiguities, but I do hope you win
the bet!

In practice, my code for initializing each entry in a menu looks like the
following (Name's are strings):
     AddItemProc( Name1, Proc1 );
     AddItemProc( Name2, Proc2 );
     ...
I would like one of these Proc's to be an object method:
     AddItemProc( Name3, Obj.Method );

Currently, I have to resort to the following code:
     procedure ObjMethod;
     begin
       Obj.Method;
     end;
     AddItemProc( Name3, ObjMethod );

Thank you for your kind offer,

Daniel Lewart
d-lewart@uiuc.edu

dslg0849@uxa.cso.uiuc.edu (Daniel S. Lewart) (12/05/90)

The following are excerpts from a note sent to me by Mark Garlanger:
> What you have to remember is that each method has a 'Self' parameter.  That
> is   Obj.Method;   can be thought of as  Method(Obj);  look on page 17,18 of
> Turbo 5.5 OOP Guide.  So when you try to assign a method to a procedure
> variable, there are two addresses that need to be saved(Obj and the address of
> Method).  Since the compiler only has room for one address in the procedure
> variable, it prints out the compiler error.
> ...
> To me, this looks like the only way to do it.  Maybe someone else out there
> knows another solution to this.   Sorry I couldn't be of more help.

I believe that this is the correct explanation of my problem.  My last question
is whether @ can be applied to an object method.  The OOP Guide says 'yes', but
my experience says 'no'.

Thanks to everyone who helped,
Dan
d-lewart@uiuc.edu

dmurdoch@watserv1.waterloo.edu (D.J. Murdoch - Statistics) (12/06/90)

In article <1990Dec4.232438.927@ux1.cso.uiuc.edu> dslg0849@uxa.cso.uiuc.edu (Daniel S. Lewart) writes:
>I believe that this is the correct explanation of my problem.  My last question
>is whether @ can be applied to an object method.  The OOP Guide says 'yes', but
>my experience says 'no'.


You seem to be allowed to do it if you specify the method with a type prefix,
but not with a variable prefix.  For example:

type
  myobj = object
    constructor init;
    procedure static;
    procedure virt; virtual;
  end;
{  code for init, static, and virt omitted... }

var
  o : myobj;
  p : pointer;
begin
  p := @myobj.static; { these first two work }
  p := @myobj.virt;
  o.init;
  p := @o.static;     { these last two don't compile }
  p := @o.virt;
end.

Duncan Murdoch

streich@tigger.Colorado.EDU (Mark Streich) (12/07/90)

dmurdoch@watserv1.waterloo.edu (D.J. Murdoch - Statistics) writes:
>You seem to be allowed to do it [get address of object method] if you 
>specify the method with a type prefix, but not with a variable prefix.  
>For example:
>
>type
>  myobj = object
>    constructor init;
>    procedure static;
>    procedure virt; virtual;
>  end;
>{  code for init, static, and virt omitted... }
>
>var
>  o : myobj;
>  p : pointer;
>begin
>  p := @myobj.static; { these first two work }
>  p := @myobj.virt;
>  o.init;
>  p := @o.static;     { these last two don't compile }
>  p := @o.virt;
>end.

This looks quite suspicious because you're taking the address of a class,
and not the address of an *instance* of the class.  Two instances may 
(obviously?) have different virtual methods.  As a comparison, it looks
like you're taking the address of the integer type rather than an integer
variable. (i.e.,  p := @integer   rather than  p := @i { of type integer })

Does this run correctly with different instances of the object?

Mark Streich
streich@tigger.colorado.edu

dmurdoch@watstat.waterloo.edu (Duncan Murdoch) (12/10/90)

In article <1990Dec7.153019.23716@csn.org> streich@tigger.Colorado.EDU (Mark Streich) writes:
>
>This looks quite suspicious because you're taking the address of a class,
>and not the address of an *instance* of the class.  Two instances may 
>(obviously?) have different virtual methods.  

It wasn't the address of the class, rather tthe address of the entry
point of a method defined 
within the class.  (Please excuse my bouncy keyboardd!  Nortthgatte has 
promised me a replacement any day now; when it arrives, I should be able to
type again.)  But your commment aboutt virtual methods is right on:  there's
no easy way to find the appropriate virtual method for an instance, other than
just calling it.  

In fact, it says somewhere in the manual that the "@" 
operattor applied to routines is useless as long as you stay within TP; it's
just provided for completeness, in case you want to pass the address to 
some assembly code.


Duncan Murdoch