Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2002-12

Passing Methods as Callback Procedures?

9 messages · 5 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Jon David Sawyer

Ok, I've got some code that looks like this:

fCollection.ForEach(@Self.DoEach);

Now when DoEach() is called its Self and the Self above are not the same...

Is this supposed to happen?

Unknown author
Show quoted text 8 lines
Ok, I've got some code that looks like this: fCollection.ForEach(@Self.DoEach); Now when DoEach() is called its Self and the Self above are not the same... Is this supposed to happen?

Yes. 'Self' refers to the Instance you currently reside within. So:

procedure TMyClass.dosomething(..);
begin
  //Self is the instance of TMyClass
end;
procedure TCollection.ForEach(..);
begin
  //Self is the instance of TCollection
end;

Therefore, as 'Self' refers to the Instance the code belongs to, Self will differ in every unique class instance.

What is the parameter for the 'TCollection.ForEach' method? I assume it's a typed method pointer? You should be able to just use the following:

fCollection.ForEach(DoEach); //assign this within the class that owns 'DoEach'.

You don't *need* to use Self, unless your class is out of scope, for example accessed within a 'with' statement and clashes with a class method/property for the with'd class.

e.g.

  procedure TForm1.Button1Clicked(sender: TObject);
  begin
    Caption := 'wabble'; // the form
    with sender as TButton do begin
      Caption := 'wibble'; //the button not the form
      Self.Caption := 'wobble'; //the form
    end;
  end;

Matt

---------------------------------------------
This message was sent using Mistral WebMail.
http://www.mistral.co.uk/

Judison
to Jon David Sawyer: Ok, I've got some code that looks like this: fCollection.ForEach(@Self.DoEach); Now when…

Hi,

Ok, I've got some code that looks like this: fCollection.ForEach(@Self.DoEach);

fCollection is a TCollection?
My TCollection does not have ForEach ;) (1.1 CVS 2002/12/13)

Show quoted text 6 lines
Now when DoEach() is called its Self and the Self above are not the same... Is this supposed to happen?

It depends on ForEach declaration.

if it is something like this:

procedure ForEach(CallBack: procedure(x: integer));

I really don't know if FPC will compile it, as your DoEach is a method (procedure of object) I hope you's ForEach declaration is something like:

procedure ForEach(CallBack: procedure(x:integer) of object);
Normally you have a Type
type
  TForEachCallBackProc = procedure(x: integer) of object;

a type "procedure" is just a pointer to de procedure, a "procedure of object" is (I Think) a record, with a pointer to a procedure and other to the context (Self).... (I don't know exactly how OO works in FPC)

I hope this can help you
Your Friend,
Judison

Jon David Sawyer
to Judison
Judison wrote 11 lines
Hi, On Sun, 15 Dec 2002 15:32:43 +0000 Jon David Sawyer wrote: > Ok, I've got some code that looks like this: > > fCollection.ForEach(@Self.DoEach); fCollection is a TCollection? My TCollection does not have ForEach ;) (1.1 CVS 2002/12/13)

Its in the docs ^_^ I dunno why you don't have it ^_^

Show quoted text 13 lines
> > Now when DoEach() is called its Self and the Self above > are not the same... > > Is this supposed to happen? > It depends on ForEach declaration. if it is something like this: procedure ForEach(CallBack: procedure(x: integer));
Procedure ForEach(Callback: Procedure(Item: Pointer));
Show quoted text 15 lines
I really don't know if FPC will compile it, as your DoEach is a method (procedure of object) I hope you's ForEach declaration is something like: procedure ForEach(CallBack: procedure(x:integer) of object); Normally you have a Type type TForEachCallBackProc = procedure(x: integer) of object; a type "procedure" is just a pointer to de procedure, a "procedure of object" is (I Think) a record, with a pointer to a procedure and other to the context (Self).... (I don't know exactly how OO works in FPC) I hope this can help you Your Friend, Judison

FPC Compiles without complaints.. It doesn't even warn me that I'm intermixing Procedures of Object and Procedures; I had assumed this meant that it would work. I'm also using FPC Devel 1.1.

As a fix I just created my own object that inherited from tCollection and accepted Procedure or Object as a callback. ^_^ It worked.. I just think the compiler should warn/fault on you if you make that kind of mistake ^_^

_______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Jon David Sawyer
to Unknown author: Yes. 'Self' refers to the Instance you currently reside within. So: procedure…
Show quoted text 52 lines
> Ok, I've got some code that looks like this: > > fCollection.ForEach(@Self.DoEach); > > Now when DoEach() is called its Self and the Self above > are not the same... > > Is this supposed to happen? Yes. 'Self' refers to the Instance you currently reside within. So: procedure TMyClass.dosomething(..); begin //Self is the instance of TMyClass end; procedure TCollection.ForEach(..); begin //Self is the instance of TCollection end; Therefore, as 'Self' refers to the Instance the code belongs to, Self will differ in every unique class instance. What is the parameter for the 'TCollection.ForEach' method? I assume it's a typed method pointer? You should be able to just use the following: fCollection.ForEach(DoEach); //assign this within the class that owns 'DoEach'. You don't *need* to use Self, unless your class is out of scope, for example accessed within a 'with' statement and clashes with a class method/property for the with'd class. e.g. procedure TForm1.Button1Clicked(sender: TObject); begin Caption := 'wabble'; // the form with sender as TButton do begin Caption := 'wibble'; //the button not the form Self.Caption := 'wobble'; //the form end; end; Matt

I belive you missunderstood what I was trying to do: I had My object which used another object. That otehr object was a tCollection. tCOllection has a method in which you can pass a procedure to process each individual item in the collection.

I was trying to pass My object's item handler , MyObject.DoEach, as the callback procedure for ForEach(); ie:
fCOllection.ForEach(@Self.DoEach);

The compiler doesn't complain about this code. However the correct instance of the object is not called when DoEach() is called.

My problem is that prior to going into ForEach() self equals something diffrent than when ForEach() calls DoEach().

Show quoted text 10 lines
--------------------------------------------- This message was sent using Mistral WebMail. http://www.mistral.co.uk/ _______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Karagiannidis Savvas
to Jon David Sawyer
PM Jon David Sawyer wrote 23 lines
On Mon, 2002-12-16 at 13:57, wrote: > > Ok, I've got some code that looks like this: > > > > fCollection.ForEach(@Self.DoEach); > > > > Now when DoEach() is called its Self and the Self above > > are not the same... > > > > Is this supposed to happen? > > Yes. 'Self' refers to the Instance you currently reside within. So: > > procedure TMyClass.dosomething(..); > begin > //Self is the instance of TMyClass > end; > > procedure TCollection.ForEach(..); > begin > //Self is the instance of TCollection > end; > > Therefore, as 'Self' refers to the Instance the code belongs to, Self

will

> differ in every unique class instance. > > What is the parameter for the 'TCollection.ForEach' method? I assume

it's a

> typed method pointer? You should be able to just use the following: > > fCollection.ForEach(DoEach); //assign this within the class that owns

'DoEach'.

> > You don't *need* to use Self, unless your class is out of scope, for

example

> accessed within a 'with' statement and clashes with a class

method/property for

Show quoted text 36 lines
> the with'd class. > > e.g. > > procedure TForm1.Button1Clicked(sender: TObject); > begin > Caption := 'wabble'; // the form > > with sender as TButton do begin > > Caption := 'wibble'; //the button not the form > > Self.Caption := 'wobble'; //the form > > end; > end; > > > Matt > > I belive you missunderstood what I was trying to do: I had My object which used another object. That otehr object was a tCollection. tCOllection has a method in which you can pass a procedure to process each individual item in the collection. I was trying to pass My object's item handler , MyObject.DoEach, as the callback procedure for ForEach(); ie: fCOllection.ForEach(@Self.DoEach); The compiler doesn't complain about this code. However the correct instance of the object is not called when DoEach() is called. My problem is that prior to going into ForEach() self equals something diffrent than when ForEach() calls DoEach(). >

In ForEach you must pass two parameters.
The first must be a pointer to the object whose method you want to call and the second must be the pointer to the object's method.

Note that fCollection must accept the second parameter as a pointer to a procedure,
but the type of the procedure is different than the object's method. The difference between them is that
the procedure has an extra parameter, which must be the first parameter you pass to the procedure,
and must be the pointer that points to the object whose method you wish to call...

for example :

TDoEachProc = procedure (objptr : pointer;  ...... (actual method
parameters)  );
fCollection = class
   procedure ForEach( callbackobj : pointer; callbackproc : TDoEachProc );
end;
procedure fCollection.ForEach ( callbackobj : pointer; callbackproc :
TDoEachProc );
begin
  callbackproc( callbackobj ,  ... parameters for the method... );
end;

Now, in the other object, you can use

procedure AnObject.DoEach(...)
begin
...
end;
procedure AnObject.SetCallBack;
var p : pointer;
begin
  ...
  p := @DoEach;
  fCollection.ForEach(Self,TDoEachProc(p));
end;

This should work for you, BUT I don't think you should do something like that!
I'm sure that there is a better way of doing what you want...

Judison
to Jon David Sawyer: Its in the docs ^_^ I dunno why you don't have it ^_^ Procedure ForEach(Callback:…
Show quoted text 6 lines
> > fCollection is a TCollection? > My TCollection does not have ForEach ;) (1.1 CVS 2002/12/13) Its in the docs ^_^ I dunno why you don't have it ^_^

I look at the sources, and, as you say that its in the docs, I look at tha docs too, but I don't find any ForEach... But a grep show me that you are using TCollection of Objects.pp... :) and I was ;)

I don't know much about "objects".... :)
there is no "of object" in objects.pp

you are using TP compatible mode?

Show quoted text 10 lines
... FPC Compiles without complaints.. It doesn't even warn me that I'm intermixing Procedures of Object and Procedures; I had assumed this meant that it would work. I'm also using FPC Devel 1.1. As a fix I just created my own object that inherited from tCollection and accepted Procedure or Object as a callback. ^_^ It worked.. I just think the compiler should warn/fault on you if you make that kind of mistake ^_^

Well, it isn't with me :)

but, think about to use -S2 and use classes instead of objects.

Your friend,
Judison

Jon David Sawyer
to Karagiannidis Savvas: will it's a 'DoEach'. example method/property for In ForEach you must pass two parameters.
Karagiannidis Savvas wrote 128 lines
On Monday, December 16, 2002 10:27 PM Jon David Sawyer wrote : > On Mon, 2002-12-16 at 13:57, wrote: > > > Ok, I've got some code that looks like this: > > > > > > fCollection.ForEach(@Self.DoEach); > > > > > > Now when DoEach() is called its Self and the Self above > > > are not the same... > > > > > > Is this supposed to happen? > > > > Yes. 'Self' refers to the Instance you currently reside within. So: > > > > procedure TMyClass.dosomething(..); > > begin > > //Self is the instance of TMyClass > > end; > > > > procedure TCollection.ForEach(..); > > begin > > //Self is the instance of TCollection > > end; > > > > Therefore, as 'Self' refers to the Instance the code belongs to, Self will > > differ in every unique class instance. > > > > What is the parameter for the 'TCollection.ForEach' method? I assume it's a > > typed method pointer? You should be able to just use the following: > > > > fCollection.ForEach(DoEach); //assign this within the class that owns 'DoEach'. > > > > You don't *need* to use Self, unless your class is out of scope, for example > > accessed within a 'with' statement and clashes with a class method/property for > > the with'd class. > > > > e.g. > > > > procedure TForm1.Button1Clicked(sender: TObject); > > begin > > Caption := 'wabble'; // the form > > > > with sender as TButton do begin > > > > Caption := 'wibble'; //the button not the form > > > > Self.Caption := 'wobble'; //the form > > > > end; > > end; > > > > > > Matt > > > > > I belive you missunderstood what I was trying to do: > I had My object which used another object. That otehr object was > a tCollection. tCOllection has a method in which you can pass > a procedure to process each individual item in the collection. > > I was trying to pass My object's item handler , MyObject.DoEach, as > the callback procedure for ForEach(); ie: > fCOllection.ForEach(@Self.DoEach); > > The compiler doesn't complain about this code. However the correct > instance of the object is not called when DoEach() is called. > > My problem is that prior to going into ForEach() self equals something > diffrent than when ForEach() calls DoEach(). > > In ForEach you must pass two parameters. The first must be a pointer to the object whose method you want to call and the second must be the pointer to the object's method. Note that fCollection must accept the second parameter as a pointer to a procedure, but the type of the procedure is different than the object's method. The difference between them is that the procedure has an extra parameter, which must be the first parameter you pass to the procedure, and must be the pointer that points to the object whose method you wish to call... for example : TDoEachProc = procedure (objptr : pointer; ...... (actual method parameters) ); fCollection = class procedure ForEach( callbackobj : pointer; callbackproc : TDoEachProc ); end; procedure fCollection.ForEach ( callbackobj : pointer; callbackproc : TDoEachProc ); begin callbackproc( callbackobj , ... parameters for the method... ); end; Now, in the other object, you can use procedure AnObject.DoEach(...) begin ... end; procedure AnObject.SetCallBack; var p : pointer; begin ... p := @DoEach; fCollection.ForEach(Self,TDoEachProc(p)); end; This should work for you, BUT I don't think you should do something like that! I'm sure that there is a better way of doing what you want...

If there is a better way of doing this I'd be most intrested in hearing? I *was* able to get the code worknig the way wanted by overrideing tCollection.ForEach with one that took a Procedure Of Object; callback. But *IF* there is an even better way then I'm all for it! ^_^

[to the message board]
Sorry about the multipul replys. for some reason my Email client puked on me yesterday. (Evolution)

_______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Jonas Maebe
to Judison: On Mon, 16 Dec 2002 20:23:34 +0000 I look at the sources, and, as you say that its in the…
Judison wrote 7 lines
I look at the sources, and, as you say that its in the docs, I look at tha docs too, but I don't find any ForEach... But a grep show me that you are using TCollection of Objects.pp... :) and I was ;) I don't know much about "objects".... :) there is no "of object" in objects.pp

The ForEach methods of objects.pp don't expect (and as such cannot work with) methods as function parameters, they only work with *nested* procedures. That the fact that you pass a pointer to a method (or a non-nested procedure) to a ForEach method instead of a nested procedure is wrong, cannot be detected by the compiler because the type of the parameter of TCollection.ForEach is simply an untyped pointer (that's the way it was defined by Borland). Besides, there is no way to specify a procedure-variable type that only allows nested procedures.

Jonas