Solved

Callback functions for both object and non-object functions

Posted on 2007-04-10
8
565 Views
Last Modified: 2011-09-20
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
Comment
Question by:IgnaceLamine
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 2
  • 2
8 Comments
 
LVL 21

Expert Comment

by:ziolko
ID: 18882345
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
 

Author Comment

by:IgnaceLamine
ID: 18884461
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
 
LVL 21

Accepted Solution

by:
ziolko earned 200 total points
ID: 18886155
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!

 
LVL 1

Expert Comment

by:swiatlo
ID: 18888343
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
 
LVL 1

Assisted Solution

by:swiatlo
swiatlo earned 50 total points
ID: 18888474
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
 
LVL 21

Expert Comment

by:ziolko
ID: 18888879
huh it's hard to tell which is better, but event oriented solution is more
"delphi like":)

ziolko
0
 
LVL 21

Expert Comment

by:ziolko
ID: 18888918
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
 

Author Comment

by:IgnaceLamine
ID: 18890312
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

Technology Partners: 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!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
Although Jacob Bernoulli (1654-1705) has been credited as the creator of "Binomial Distribution Table", Gottfried Leibniz (1646-1716) did his dissertation on the subject in 1666; Leibniz you may recall is the co-inventor of "Calculus" and beat Isaac…
In a recent question (https://www.experts-exchange.com/questions/29004105/Run-AutoHotkey-script-directly-from-Notepad.html) here at Experts Exchange, a member asked how to run an AutoHotkey script (.AHK) directly from Notepad++ (aka NPP). This video…

749 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question