Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 630
  • Last Modified:

Callback functions for both object and non-object functions

Using Delphi I want to use callback functions as parameters of a procedure.
Let's say I write an optimization routine declared as
procedure goldensearch(f: TGoalFunction;  ax, bx, cx, tol: Real; var xmin, fmin: Real);
TGoalFunction is a callback function that I can define as
TGoalFunction = function(x: Real): Real of object;
or as
TGoalFunction = function(x: Real): Real;
In the first case the function has to be a memberfunction of a class in the second case it is is not a member function.

Now I want to use the goldensearch with both object member functions en non-object functions. How do I do that? It seems now to me that I have to program two nearly identical goldensearch procedures with the only difference the parameter with and without "of object".

Is there a way to handle both situations in one implementation?
0
IgnaceLamine
Asked:
IgnaceLamine
  • 4
  • 2
  • 2
2 Solutions
 
ziolkoCommented:
very simply:

function NonObjectGoal(x: Real):Real;
begin
.
.
.
end;

TSomeObject = class()
  function ObjectGoal(x: Real):Real;
end;

function TSomeObject.ObjectGoal(x: Real):Real;
begin
  Result := NonObjectGoal(x);
end;

this way you can use it in two ways:
goldensearch(NonObjectGoal, ....)
or
goldensearch(someobject.ObjectGoal, ....)

ziolko.
0
 
IgnaceLamineAuthor Commented:
If I am correct, you are saying that I should always choose the "function of object" parameter type. If my goalfunction is part of a class, then I'm lucky and can use it straight away, if it's not part of a class I should create a dummy class for it. Looks like a hack to me, but usable. I wish there were a more elegant solution.

Any other suggestions? Solutions?
0
 
ziolkoCommented:
you can of course use object method as callback in same object as goldensearch() or
creating dummy class for callback only might work but that's not "elegant" way.
so i suggest two ways:
1. use non-object callback function
2. if you want to stick to objects use event that would more "delphi like" and clear to understand for most delphi devs.

TObjectGoalEvent = function(Sender:TObject;x: Real):Real of object;

TSomeClass = class(TObject)
private
  FOnObjectGoal: TObjectGoalEvent;
public
  procedure goldensearch(f: TGoalFunction;  ax, bx, cx, tol: Real; var xmin, fmin: Real);
  property OnObjectGoal: TObjectGoalEvent read FOnObjectGoal write FOnObjectGoal;
end;
.
.
.
procedure
TSomeClass.goldensearch(f: TGoalFunction;  ax, bx, cx, tol: Real; var xmin, fmin: Real);
begin
.
.
.
  if Assigned(FOnObjectGoal) then
    FOnObjectGoal(Self, your x value here);
.
.
.
end;

TCallback = class(TObject)
  function MyOnObjectGoalEventHandler(Sender: TObject;x: Real);
end;


var someobj: TSomeClass;
      callbackobj: TCallback;

someobj.OnObjectGoal := callbackobj.MyOnObjectGoalEventHandler

ziolko.
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
swiatloCommented:
Investigate TMethod type in your help file.
It has two fields. Code, Data: Pointer;
Data points to an object, Code points to execution routine - method, but I think you can put a function addres in there.

var
  sp: procedure(val:Integer) of Object;
begin
      TMethod(sp).code:=funcaddr;
      TMethod(sp).data:=obj;

     if TMethod(sp).data<>nil then
       sp(5)                               //Execute as an object method
    else
       TMethod(sp).code(5) //Execute as stand alone function



0
 
swiatloCommented:
Myabe this would help, but I think that ziolko's warp a funciton is a better idea


unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TForm1 = class(TForm)
    ObjFunc: TButton;
    Edit1: TEdit;
    StdFun: TButton;
    procedure ObjFuncClick(Sender: TObject);
    procedure StdFunClick(Sender: TObject);
  private
    { Private declarations }
    function formsinttostr(val:integer):string;
    procedure ExecuteFunction(tm:TMethod);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

function TForm1.formsinttostr(val:integer):string;
begin
  result:=inttostr(val);
end;

procedure TForm1.ExecuteFunction(tm:TMethod);
var
  sp: function(val:Integer):string of Object;
  fun: function(val:Integer):string;
begin

     if tm.data<>nil then
       begin
         TMethod(sp).code:=tm.code;
         TMethod(sp).data:=tm.data;
         Edit1.Text:=sp(5);                              //Execute as an object method
       end
     else
       begin
         fun:=tm.Code;
         Edit1.Text:=fun(7);            //Execute as stand alone function
       end;
end;

procedure TForm1.ObjFuncClick(Sender: TObject);
var
  sp: function(val:Integer):string of Object;
begin
  sp:=formsinttostr;
  ExecuteFunction(TMethod(sp));
end;

procedure TForm1.StdFunClick(Sender: TObject);
var
  tm:TMethod;
begin
  tm.code:=@inttostr;
  tm.data:=nil;
  ExecuteFunction(tm);
end;

end.
0
 
ziolkoCommented:
huh it's hard to tell which is better, but event oriented solution is more
"delphi like":)

ziolko
0
 
ziolkoCommented:
btw. with event like solution it's very easy to implement different behaviour
for handling "callback":

TCallback = class(TObject)
  function MyOnObjectGoalEventHandler_v1(Sender: TObject;x: Real);
  function MyOnObjectGoalEventHandler_v2(Sender: TObject;x: Real);
  function MyOnObjectGoalEventHandler_v3(Sender: TObject;x: Real);
  function MyOnObjectGoalEventHandler_v4(Sender: TObject;x: Real);
  function MyOnObjectGoalEventHandler_v5(Sender: TObject;x: Real);
end;

or

TCallback_v1 = class(TObject)
  function MyOnObjectGoalEventHandler(Sender: TObject;x: Real);
end;
TCallback_v2 = class(TObject)
  function MyOnObjectGoalEventHandler(Sender: TObject;x: Real);
end;
TCallback_v3 = class(TObject)
  function MyOnObjectGoalEventHandler(Sender: TObject;x: Real);
end;
TCallback_v4 = class(TObject)
  function MyOnObjectGoalEventHandler(Sender: TObject;x: Real);
end;
TCallback_v5 = class(TObject)
  function MyOnObjectGoalEventHandler(Sender: TObject;x: Real);
end;

and hook desired implementation

ziolko.
0
 
IgnaceLamineAuthor Commented:
Thanks ziolko, yeah I guess events are the way to go in Delphi. My only issue is that I don't like to use OOP stuff for core mathematical routines (in this case an optimization routine), which I like to keep procedural, but I might change my mind.

Swiatlo, you showed some very interesting stuff with the TMethod type. Not something I would use in practice, but the insight is worth a few points ;)
0

Featured Post

Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

  • 4
  • 2
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now