Solved

Callback functions for both object and non-object functions

Posted on 2007-04-10
8
557 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
  • 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
Courses: Start Training Online With Pros, Today

Brush up on the basics or master the advanced techniques required to earn essential industry certifications, with Courses. Enroll in a course and start learning today. Training topics range from Android App Dev to the Xen Virtualization Platform.

 
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

Courses: Start Training Online With Pros, Today

Brush up on the basics or master the advanced techniques required to earn essential industry certifications, with Courses. Enroll in a course and start learning today. Training topics range from Android App Dev to the Xen Virtualization Platform.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
code issue 8 126
Help on project with Soap 10 52
Working with hours 3 54
Create a path if not exists 7 76
The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
This Micro Tutorial will give you a basic overview how to record your screen with Microsoft Expression Encoder. This program is still free and open for the public to download. This will be demonstrated using Microsoft Expression Encoder 4.
Sending a Secure fax is easy with eFax Corporate (http://www.enterprise.efax.com). First, just open a new email message. In the To field, type your recipient's fax number @efaxsend.com. You can even send a secure international fax — just include t…

816 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

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now