A r t i c l e s
Navigation

Note: This site is
a bit older, personal views
may have changed.

M a i n P a g e

D i r e c t o r y

Procedure vs Procedure Of Object Hack


See also Procedure Bound To Method Without RTTI Hack
Ever want to use a regular procedure when a procedure is required to be 'of object'?

I'm not sure if this is safe to do, but using some tricks we can turn a regular procedure type into being compatible with a procedure method inside a class, i.e a procedure of object bound to a plain procedure.

Note the {$M+} switch is used to turn on 'type information', otherwise the program below won't execute the Tx.P() method.

program test; {$mode objfpc} {$H+}{$M+}

type 
  Tx = class
  //  published
    procedure p;
  end;

procedure Tx.p;
begin
  writeln('proc test');
end;

var 
  x: Tx;
  p: procedure;  // normally we would need procedure OF OBJECT

begin
  x:= Tx.create;
  pointer(p):= x.MethodAddress('p');
  if assigned(p) then 
    p()  // call a regular procedure and not 'of object'? Magic.
  else 
    writeln('unassigned');
  x.free;
  readln;
end.

And now for the real trickery:
program test29; {$mode objfpc} {$H+}{$M+}

type 
  Tx = class
    procedure p;
    procedure test(i: integer);
  private
    s: string;
  end;

procedure Tx.p;
begin
  writeln('proc test 1');
  // how does this method know about SELF? take a guess
  self.s:= 'hello ';
  self.s:= 'hello ' + s + s;
  writeln(self.s);
end;


procedure Tx.test(i: integer);
begin
  writeln('proc test 2');
  // how does this method know about SELF? take a guess
  self.s:= 'hello ';  
  self.s:= 'hello ' + s + s + ' see number: ';
  writeln(self.s, i);
end;

var 
  x: Tx;
  // normally we would need procedure OF OBJECT
  p: procedure(fakeself: pointer);  
  // the pointer acts as our object SELF
  test: procedure(fakeself: pointer; i: integer);  

  // alternatively: don't have to use a pointer.. we can use Tx
  // test: procedure(fakeself: Tx; i: integer);  


begin
  x:= Tx.create;
  // bind regular procedures to an object method
  pointer(p):= x.MethodAddress('p');
  pointer(test):= x.MethodAddress('test');
  if assigned(p) then 
  begin
    // now launch the procedures
    p(pointer(x));           
    test(pointer(x), 600);  { pointer is our hidden SELF param }
  end else 
    writeln('unassigned');
  x.free;
  readln;
end.

Points/theories to think about and question:
  • a regular procedure can be faked/binded to an object method
  • regular procedures have benefits, such as exportable from DLL, or simplicity when an object/class is not needed.
  • how to obtain object instance if we were playing with DLL? Get it/export it using something like GetObjInstance()
  • VMT/RTTI (as and is) issues.. think about problems there


About
This site is about programming and other things.
_ _ _