Sign in Join

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

Mailing lists / fpc-devel / 2009-09

comparing methods

32 messages · 16 people · –

Reply by email Subscribe to this list Your subscription

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

Mattias Gärtner

Hi,

Can someone explain why in mode objfpc comparing methods only compares the address, but not the instance?
For example:

   a:=TMyClass.Create;
   b:=TMyClass.Create;
   if @a.test = @b.test then writeln('the same method');

This results in strange behaviors, when using the following code (from the FCL):

property AfterConnect: TNotifyEvent read FAfterConnect write SetAfterConnect;
procedure TCustomConnection.SetAfterConnect(const AValue: TNotifyEvent);
begin
   if FAfterConnect=AValue then exit;
   FAfterConnect:=AValue;
end;

Mattias

Reply by email

Michael Schnell
to Mattias Gärtner
Mattias Gärtner wrote
Can someone explain why in mode objfpc comparing methods only compares the address, but not the instance?

Seems perfectly logical to me (@ = Address of, in this case "code address", the code is the same for all instances of a class).

-Michael

Reply by email

Thaddy
to Mattias Gärtner: Can someone explain why in mode objfpc comparing methods only compares the address, but…
Mattias Gärtner wrote 30 lines
Hi, Can someone explain why in mode objfpc comparing methods only compares the address, but not the instance? For example: a:=TMyClass.Create; b:=TMyClass.Create; if @a.test = @b.test then writeln('the same method'); This results in strange behaviors, when using the following code (from the FCL): property AfterConnect: TNotifyEvent read FAfterConnect write SetAfterConnect; procedure TCustomConnection.SetAfterConnect(const AValue: TNotifyEvent); begin if FAfterConnect=AValue then exit; FAfterConnect:=AValue; end; Mattias _______________________________________________ fpc-devel maillist - http://lists.freepascal.org/mailman/listinfo/fpc-devel

The deep copy versus shallow copy problem.
Depending on what you want. here it is implementing a deep compare, (an instance full copy) instead of a shallow compare (a pointer copy). Both are valid paradigms, but also -very, very - basic computer science. You for some reason want a shallow compare, which may or may not be correct, depending on your code.

Reply by email

Mattias Gärtner
to Michael Schnell: Seems perfectly logical to me (@ = Address of, in this case "code address", the code is…

Zitat von Michael Schnell :

Show quoted text 6 lines
Mattias Gärtner wrote: > Can someone explain why in mode objfpc comparing methods only compares > the address, but not the instance? Seems perfectly logical to me (@ = Address of, in this case "code address", the code is the same for all instances of a class).
;

The @ operator is more than "address of".

Mattias

Reply by email

Jonas Maebe
to Mattias Gärtner
Mattias Gärtner wrote 12 lines
> > Mattias Gärtner wrote: >> Can someone explain why in mode objfpc comparing methods only >> compares >> the address, but not the instance? > > Seems perfectly logical to me (@ = Address of, in this case "code > address", the code is the same for all instances of a class). ; The @ operator is more than "address of".

The current behaviour has been there since svn revision 1, so it's quite old and established at least (and Delphi/TP-compatible, afaik).

Jonas

Reply by email

Thaddy
to Mattias Gärtner: Zitat von Michael Schnell : ; The @ operator is more than "address of". Mattias
Mattias Gärtner wrote 13 lines
Zitat von Michael Schnell : > Mattias Gärtner wrote: >> Can someone explain why in mode objfpc comparing methods only compares >> the address, but not the instance? > > Seems perfectly logical to me (@ = Address of, in this case "code > address", the code is the same for all instances of a class). ; The @ operator is more than "address of".

Nope, it is: although there is some vmt work involved : the data part is for the new instance, not the global instance. Assigning a new method to one of the two instances your example gives makes them unequal because the instances are deep copies or rather new instances of the same class with different addresses. Hopes that helps.

If you assign to an empty variable, like

var a,b:TMyClass;
begin
b:= TMyClass.Create;
a:=b;
end;

You will get the result you expect.

Again, very basic.

Reply by email

Vincent Snijders
to Jonas Maebe: The current behaviour has been there since svn revision 1, so it's quite old and…
Jonas Maebe wrote 17 lines
On 10 Sep 2009, at 14:01, Mattias Gärtner wrote: >> >> Mattias Gärtner wrote: >>> Can someone explain why in mode objfpc comparing methods only compares >>> the address, but not the instance? >> >> Seems perfectly logical to me (@ = Address of, in this case "code >> address", the code is the same for all instances of a class). > > ; > > The @ operator is more than "address of". The current behaviour has been there since svn revision 1, so it's quite old and established at least (and Delphi/TP-compatible, afaik).

It is delphi compatible, not really intuitive, so I would welcome a change in the objfpc mode.

See:
http://bugs.freepascal.org/view.php?id=9228
http://bugs.freepascal.org/view.php?id=11868

Vincent

Reply by email

Mattias Gärtner
to Thaddy: Nope, it is: although there is some vmt work involved : the data part is for the new…

Zitat von Thaddy :

Show quoted text 20 lines
Mattias Gärtner wrote: > Zitat von Michael Schnell : > >> Mattias Gärtner wrote: >>> Can someone explain why in mode objfpc comparing methods only compares >>> the address, but not the instance? >> >> Seems perfectly logical to me (@ = Address of, in this case "code >> address", the code is the same for all instances of a class). > > ; > > The @ operator is more than "address of". > Nope, it is: although there is some vmt work involved : the data part is for the new instance, not the global instance. Assigning a new method to one of the two instances your example gives makes them unequal because the instances are deep copies or rather new instances of the same class with different addresses. Hopes that helps.

thanks for trying.

Show quoted text 9 lines
If you assign to an empty variable, like var a,b:TMyClass; begin b:= TMyClass.Create; a:=b; end; You will get the result you expect.

The 'a,b' above are pointers to mem areas. a=b compares the pointers. If a,b would be records then a=b would compare the mem. If a,b would be 'procedure of object' then a=b compares only half of the mem. This is different to both cases above.
Hope this helps.

Mattias

Reply by email

Mattias Gärtner
to Jonas Maebe: The current behaviour has been there since svn revision 1, so it's quite old and…

Zitat von Jonas Maebe :

Show quoted text 17 lines
On 10 Sep 2009, at 14:01, Mattias Gärtner wrote: >> >> Mattias Gärtner wrote: >>> Can someone explain why in mode objfpc comparing methods only compares >>> the address, but not the instance? >> >> Seems perfectly logical to me (@ = Address of, in this case "code >> address", the code is the same for all instances of a class). > > ; > > The @ operator is more than "address of". The current behaviour has been there since svn revision 1, so it's quite old and established at least (and Delphi/TP-compatible, afaik).

Yes, and since the beginning I was wondering why. Years ago I thought, there are probably cases where this is useful. But since today I hardly saw one. OTOH I saw several times code that misused it. If it is only for delphi/tp compatibility, then maybe it can be changed in mode objfpc?

Mattias

Reply by email

Mattias Gärtner
to Vincent Snijders: It is delphi compatible, not really intuitive, so I would welcome a change in the objfpc…

Zitat von Vincent Snijders :

Show quoted text 25 lines
Jonas Maebe schreef: > > On 10 Sep 2009, at 14:01, Mattias Gärtner wrote: > >>> >>> Mattias Gärtner wrote: >>>> Can someone explain why in mode objfpc comparing methods only compares >>>> the address, but not the instance? >>> >>> Seems perfectly logical to me (@ = Address of, in this case "code >>> address", the code is the same for all instances of a class). >> >> ; >> >> The @ operator is more than "address of". > > The current behaviour has been there since svn revision 1, so it's > quite old and established at least (and Delphi/TP-compatible, afaik). It is delphi compatible, not really intuitive, so I would welcome a change in the objfpc mode. See: http://bugs.freepascal.org/view.php?id=9228 http://bugs.freepascal.org/view.php?id=11868

To draw the whole picture:

var a,b: TNotifyEvent;

a=b compares only Code, not Data
a=nil compares only Data, not Code
Assigned(a) compares only Code, not Data
n.a. compares both

I wonder how many programmers know this.

Even the FCL contains code, where this leads to wrong code. More important: I don't know a place, where a=b and a=nil are used right. But I have seen a lot of code where it was used wrong.

Mattias

Reply by email

Desmond Coertzen
to Mattias Gärtner

I have done some horrible code where I needed to know the following:

If TSomeProc = procedure(....), then is it easy to determine or set entry
vector of ThatProc: TSomeProc by stating ThatProc :=
@ProcWhereTheCodeLives_InTheCodeSegment;

It gets more difficult when you work with TSomeClassProc = procedure(....) of object, because two parts are referenced here: 1) The entry vector where the code lives, 2) The heap address where the object struct lives. (Known as the Self variable in a procedure of object)

I have worked out which pointer of the two pointers belongs to the code and which to the instance with a trial. With a move operation, I was able to manipulate the two pointers, specifically to determine the address of the instance.

The @ operator only gives you access to the procedure part. Is there, or will there be, another operator to give you access to the instance address?

2009/9/10 Mattias Gärtner

Show quoted text 58 lines
Zitat von Vincent Snijders : Jonas Maebe schreef: > >> >> On 10 Sep 2009, at 14:01, Mattias Gärtner wrote: >> >> >>>> Mattias Gärtner wrote: >>>> >>>>> Can someone explain why in mode objfpc comparing methods only compares >>>>> the address, but not the instance? >>>>> >>>> >>>> Seems perfectly logical to me (@ = Address of, in this case "code >>>> address", the code is the same for all instances of a class). >>>> >>> >>> ; >>> >>> The @ operator is more than "address of". >>> >> >> The current behaviour has been there since svn revision 1, so it's quite >> old and established at least (and Delphi/TP-compatible, afaik). >> > > It is delphi compatible, not really intuitive, so I would welcome a change > in the objfpc mode. > > See: > http://bugs.freepascal.org/view.php?id=9228 > http://bugs.freepascal.org/view.php?id=11868 > To draw the whole picture: var a,b: TNotifyEvent; a=b compares only Code, not Data a=nil compares only Data, not Code Assigned(a) compares only Code, not Data n.a. compares both I wonder how many programmers know this. Even the FCL contains code, where this leads to wrong code. More important: I don't know a place, where a=b and a=nil are used right. But I have seen a lot of code where it was used wrong. Mattias _______________________________________________ fpc-devel maillist - http://lists.freepascal.org/mailman/listinfo/fpc-devel

Reply by email

Peter Vreman
to Desmond Coertzen
Desmond Coertzen wrote
I have done some horrible code where I needed to know the following: If TSomeProc = procedure(....), then is it easy to determine or set

entry

vector of ThatProc: TSomeProc by stating ThatProc := @ProcWhereTheCodeLives_InTheCodeSegment; It gets more difficult when you work with TSomeClassProc =

procedure(....)

of object, because two parts are referenced here: 1) The entry vector

where

the code lives, 2) The heap address where the object struct lives.

(Known

as the Self variable in a procedure of object) I have worked out which pointer of the two pointers belongs to the code

and

which to the instance with a trial. With a move operation, I was able to manipulate the two pointers, specifically to determine the address of

the

instance. The @ operator only gives you access to the procedure part. Is there, or will there be, another operator to give you access to the instance

address?

You can use the TMethod record to access the fields:

{$mode objfpc}
type
  tc=class
    procedure p;
  end;
procedure tc.p;
begin
end;
var
  c : tc;
begin
  writeln(hexstr(tmethod(@c.p).data));
  writeln(hexstr(tmethod(@c.p).code));
  c:=tc.create;
  writeln(hexstr(tmethod(@c.p).data));
  writeln(hexstr(tmethod(@c.p).code));
end.

Reply by email

Ivo Steinmann
to Mattias Gärtner: Zitat von Vincent Snijders : To draw the whole picture: var a,b: TNotifyEvent; a=b …
Show quoted text 51 lines
Zitat von Vincent Snijders : > Jonas Maebe schreef: >> >> On 10 Sep 2009, at 14:01, Mattias Gärtner wrote: >> >>>> >>>> Mattias Gärtner wrote: >>>>> Can someone explain why in mode objfpc comparing methods only >>>>> compares >>>>> the address, but not the instance? >>>> >>>> Seems perfectly logical to me (@ = Address of, in this case "code >>>> address", the code is the same for all instances of a class). >>> >>> ; >>> >>> The @ operator is more than "address of". >> >> The current behaviour has been there since svn revision 1, so it's >> quite old and established at least (and Delphi/TP-compatible, afaik). > > It is delphi compatible, not really intuitive, so I would welcome a > change in the objfpc mode. > > See: > http://bugs.freepascal.org/view.php?id=9228 > http://bugs.freepascal.org/view.php?id=11868 To draw the whole picture: var a,b: TNotifyEvent; a=b compares only Code, not Data a=nil compares only Data, not Code Assigned(a) compares only Code, not Data n.a. compares both I wonder how many programmers know this. Even the FCL contains code, where this leads to wrong code. More important: I don't know a place, where a=b and a=nil are used right. But I have seen a lot of code where it was used wrong. Mattias _______________________________________________ fpc-devel maillist - http://lists.freepascal.org/mailman/listinfo/fpc-devel

if that's true, then it's the biggest crap I ever heard ;) it must be fixed .... i'm using those kind of compares all over the place, but I never noticed this difference.

1. Using =nil or Assigned should result in the same.
2. a=b comparing only code is ok

Reply by email

Desmond Coertzen
to Peter Vreman: On Thu, 10 Sep 2009 14:25:26 +0000, Desmond Coertzen entry procedure(....) where (Known…

Thank you Peter.

TMethod would have been handy if i knew about this back then. For delphi compatibility, I had to do this:

program methodpointer;
uses
  Classes, sysutils;
type
  TMyEvent = procedure of object;
  TMyClass = class(TObject)
    procedure MyMethod;
  end;

{ TMyClass }

procedure TMyClass.MyMethod;
begin
end;
var
  MyEvent : TMyEvent;
  Addr    : ^TMethod;
  MyClass: TMyClass = nil;
begin
  writeln(hexStr(TMethod(TMyEvent(MyClass.MyMethod)).Code));
  writeln(hexStr(TMethod(TMyEvent(MyClass.MyMethod)).Data));
  MyClass := TMyClass.Create;
  writeln(hexStr(TMethod(TMyEvent(MyClass.MyMethod)).Code));
  writeln(hexStr(TMethod(TMyEvent(MyClass.MyMethod)).Data));
  FreeAndNil(MyClass);
end.
Peter Vreman wrote 55 lines
On Thu, 10 Sep 2009 14:25:26 +0000, Desmond Coertzen wrote: > I have done some horrible code where I needed to know the following: > > If TSomeProc = procedure(....), then is it easy to determine or set entry > vector of ThatProc: TSomeProc by stating ThatProc := > @ProcWhereTheCodeLives_InTheCodeSegment; > > It gets more difficult when you work with TSomeClassProc = procedure(....) > of object, because two parts are referenced here: 1) The entry vector where > the code lives, 2) The heap address where the object struct lives. (Known > as > the Self variable in a procedure of object) > > I have worked out which pointer of the two pointers belongs to the code and > which to the instance with a trial. With a move operation, I was able to > manipulate the two pointers, specifically to determine the address of the > instance. > > The @ operator only gives you access to the procedure part. Is there, or > will there be, another operator to give you access to the instance address? > You can use the TMethod record to access the fields: {$mode objfpc} type tc=class procedure p; end; procedure tc.p; begin end; var c : tc; begin writeln(hexstr(tmethod(@c.p).data)); writeln(hexstr(tmethod(@c.p).code)); c:=tc.create; writeln(hexstr(tmethod(@c.p).data)); writeln(hexstr(tmethod(@c.p).code)); end. _______________________________________________ fpc-devel maillist - http://lists.freepascal.org/mailman/listinfo/fpc-devel

Reply by email

Martin
to Mattias Gärtner: Zitat von Michael Schnell : ; The @ operator is more than "address of". Mattias
Mattias Gärtner wrote 10 lines
Zitat von Michael Schnell : > Mattias Gärtner wrote: >> Can someone explain why in mode objfpc comparing methods only compares >> the address, but not the instance? > Seems perfectly logical to me (@ = Address of, in this case "code > address", the code is the same for all instances of a class). ; The @ operator is more than "address of".

Most interesting.
I also always sought @Instance.Method, returns a TMethod record (that is the address of the instance and the address of the Code).

But mor interesting: There a various mails/requests about:
- overloading by result
- automatic extending a calculation to the type of the result AInteger := AByte + AByte can cause an overflow, even though the result would have enough space

Every time the answer includes something like: The evaluation of an expression (rvalue) is done independent of the type of the variable to which it will be assigned (lvalue) .
A statement I do agree with 100%.
Therefore in "Int := Byte + Byte" the rvalue is calculated using bytes. And therefore an overload by result is not possible as when evaluating what to call, the type of the lvalue is unknown.

And now I am reading this mail, and unless I misunderstood something: The result of @Instance.Method depends on the lvalue's type or the context? (assignment vs compare).

That seems to be in direct disagreement to the above statement?

Martin

Reply by email

Florian Klaempfl
to Mattias Gaertner
Show quoted text 8 lines
On Thu, 10 Sep 2009 17:52:44 +0200 Florian Klaempfl wrote: > Ivo Steinmann schrieb: >> 1. Using =nil or Assigned should result in the same. > Afaik not, this was one of the reasons for assigned. Are there any other reasons for assigned?

Distinction between f=nil and f=nil ;)? When it was introduced, I guess f()=nil was not possible.

Reply by email

Michael Van Canneyt
to Florian Klaempfl
Florian Klaempfl wrote 12 lines
Mattias Gaertner schrieb: > On Thu, 10 Sep 2009 17:52:44 +0200 > Florian Klaempfl wrote: > >> Ivo Steinmann schrieb: >>> 1. Using =nil or Assigned should result in the same. >> Afaik not, this was one of the reasons for assigned. > > Are there any other reasons for assigned? Distinction between f=nil and f=nil ;)? When it was introduced, I guess f()=nil was not possible.

Another idea was that Assigned() could test if a pointer was within range of the heap.

Michael.

Reply by email

Ivo Steinmann
to Florian Klaempfl: Afaik not, this was one of the reasons for assigned.
Show quoted text 12 lines
Ivo Steinmann schrieb: > 1. Using =nil or Assigned should result in the same. > Afaik not, this was one of the reasons for assigned. _______________________________________________ fpc-devel maillist - http://lists.freepascal.org/mailman/listinfo/fpc-devel

well, nobody seems to know it... eg. if you go through code in rtl (classes, etc...) sometimes =nil is used, sometimes Assigned. it's a complete random mix. I don't think that this "mix" was intention.

Reply by email

Nino Luciani
to Florian Klaempfl: Afaik not, this was one of the reasons for assigned.
Florian Klaempfl wrote 5 lines
Ivo Steinmann schrieb: > 1. Using =nil or Assigned should result in the same. Afaik not, this was one of the reasons for assigned.

I have always used Assigned() to test whether a pointer is 'valid' or is nil. Thus Assiged() should return False if pointer is nil?

procedure Test;
var
  myPtr : PChar;
begin
  // Pointer variables are not set to nil by default
  if Assigned(myPtr) then
    ShowMessage('myPtr is not nil')
  else
    ShowMessage('myPtr is nil');
  // So we must set them to nil to be sure that they are undefined
  myPtr := Nil;
  if Assigned(myPtr) then
   ShowMessage('myPtr is still not nil')
  else
   ShowMessage('myPtr is nil');
end;

if you don't agree, don't blame me.
http://www.delphibasics.co.uk/RTL.asp?Name=Assigned

_______________________________________________ fpc-devel maillist - http://lists.freepascal.org/mailman/listinfo/fpc-devel

Reply by email

Sergei Gorelkin
to Michael Van Canneyt: Another idea was that Assigned() could test if a pointer was within range of the heap.…
Michael Van Canneyt wrote 20 lines
On Thu, 10 Sep 2009, Florian Klaempfl wrote: > Mattias Gaertner schrieb: >> On Thu, 10 Sep 2009 17:52:44 +0200 >> Florian Klaempfl wrote: >> >>> Ivo Steinmann schrieb: >>>> 1. Using =nil or Assigned should result in the same. >>> Afaik not, this was one of the reasons for assigned. >> >> Are there any other reasons for assigned? > > Distinction between f=nil and f=nil ;)? When it was introduced, I guess > f()=nil was not possible. Another idea was that Assigned() could test if a pointer was within range of the heap.

To my knowledge, in Delphi Assigned() tests only the high-order word of the pointer, thus returning False for everything below 64k.

Sergei

Reply by email

Michael Schnell
to Mattias Gärtner: Zitat von Michael Schnell : ; The @ operator is more than "address of". Mattias
Mattias Gärtner wrote
The @ operator is more than "address of".

Hmm "Address of" is not that simple in itself. :)

With a "Procedure of Object", "@" of course handles the Self pointer, too.

I suppose to find the address of a function "@" uses the Virtual Method Table found with the Self pointer.

So in fact there are (at least) two ways of implementing a compare between two pointers to "Procedure of Object" variables, that IMHO both make sense:

1) Simply compare the Self and the Address part (the same function of two implementations of a class are different)

2) Compare only the address (the same function of two implementations of a class are identical, unless overloaded by a child's function).

I think it's a matter of taste (I do vote for (2) ).

-Michael

Reply by email

Mattias Gärtner
to Michael Schnell

Zitat von Michael Schnell :

Show quoted text 23 lines
Mattias Gärtner wrote: > > The @ operator is more than "address of". > Hmm "Address of" is not that simple in itself. :) With a "Procedure of Object", "@" of course handles the Self pointer, too. I suppose to find the address of a function "@" uses the Virtual Method Table found with the Self pointer. So in fact there are (at least) two ways of implementing a compare between two pointers to "Procedure of Object" variables, that IMHO both make sense: 1) Simply compare the Self and the Address part (the same function of two implementations of a class are different) 2) Compare only the address (the same function of two implementations of a class are identical, unless overloaded by a child's function). I think it's a matter of taste (I do vote for (2) ).

No.
It is a matter of consistency.

The current comparison is not intuitive. This is proven by the many places where it used wrong and the almost zero places where it is used right (Is there any one at all?).

The problems are:

1. It exists for years, so there might be code depending on this. I doubt this.

2. It is Delphi/TP compatible. So it can not be done in mode delphi/tp. That's why I propose to change it in mode objfpc.

If the compiler team refuses to change it, can at least a "hint" be given?

Mattias

Reply by email

Martin Schreiber
to Ivo Steinmann: well, nobody seems to know it... eg. if you go through code in rtl (classes, etc...)…
Ivo Steinmann wrote 10 lines
Florian Klaempfl schrieb: > Ivo Steinmann schrieb: >> 1. Using =nil or Assigned should result in the same. > > Afaik not, this was one of the reasons for assigned. > well, nobody seems to know it... eg. if you go through code in rtl (classes, etc...) sometimes =nil is used, sometimes Assigned. it's a complete random mix. I don't think that this "mix" was intention.

IDE's (Delphi, MSEide, don't know about Lazarus) store a method index number in TMethod.Code in published method properties because there is no code for the handler available at designtime, TMethod.Data is nil. For designtime running software (RTL, FCL, components...) *always* use assigned() in order to check if a method property is set before calling the handler or you will call the the indexnumber which probably want work well. ;-)
This is probably the reason using =nil or assigned() depending on the task in Classes.

Martin

Reply by email

Mattias Gaertner
to Martin Schreiber
Show quoted text 21 lines
On Thursday 10 September 2009 19:42:22 Ivo Steinmann wrote: > Florian Klaempfl schrieb: > > Ivo Steinmann schrieb: > >> 1. Using =nil or Assigned should result in the same. > > > > Afaik not, this was one of the reasons for assigned. > > > > well, nobody seems to know it... eg. if you go through code in rtl > (classes, etc...) sometimes =nil is used, sometimes Assigned. it's a > complete random mix. I don't think that this "mix" was intention. IDE's (Delphi, MSEide, don't know about Lazarus) store a method index number in TMethod.Code in published method properties because there is no code for the handler available at designtime, TMethod.Data is nil. For designtime running software (RTL, FCL, components...) *always* use assigned() in order to check if a method property is set before calling the handler or you will call the the indexnumber which probably want work well. ;-) This is probably the reason using =nil or assigned() depending on the task in Classes.

Martin, I hope you mean Data=ID and Code=nil.

Delphi and Lazarus uses this and Assigned and nil check only Code, not Data. If MSEgui allows to use components from the FCL, then it should leave Code=nil.

Mattias

Reply by email

Den Jean
to Peter Vreman: On Thu, 10 Sep 2009 14:25:26 +0000, Desmond Coertzen entry procedure(....) where (Known…
Peter Vreman wrote
You can use the TMethod record to access the fields: writeln(hexstr(tmethod(@c.p).data)); writeln(hexstr(tmethod(@c.p).code)); end.

kind of related to this,

In the Qt binding I had to revert to a non type safe method for signal hooking. Because the compiler does not always see the difference between a method provide to a procedure as a parameter and calling the method and giving the method result as a parameter to the procedure.

So I cannot directly give the hooked procedure as a parameter to a procedure, I have to do stuff like this
var M : TMethod
TSomeMethodTyp(M):=MyMethod
Hook_Signal(M);
Instead of
Hook_Signal(MyMethod)

The following code shows the problem of
default parameters confusing the compiler:
(compile with or w/o define DEFINE DEFAULT_VALUE.)

program hooks;
{$mode delphi}
{$DEFINE DEFAULT_VALUE}
uses SysUtils,Classes,Types;
{$IFNDEF DEFAULT_VALUE}
type
  TMethod_1Param = procedure(Value:integer) of object;
  procedure Hook_M_1Param(aMethod: TMethod_1Param);
  begin
  writeln('Hooked: Method.Code:',HexStr(TMethod(aMethod).Data),'
Method.Data:',HexStr(TMethod(aMethod).Code));
  TMethod_1Param(aMethod)(143);
  end;
{$ELSE}
type
  TMethod_1Param = procedure(Value:integer=0) of object;
  procedure Hook_M_1Param(aMethod: TMethod);
  begin
  writeln('Hooked: Method.Code:',HexStr(aMethod.Data),'
Method.Data:',HexStr(aMethod.Code));
  TMethod_1Param(aMethod)(143);
  end;
{$ENDIF}
type
  TC = class(TObject)
  public
  F : integer;
  constructor Create;
  {$IFNDEF DEFAULT_VALUE}
  procedure M_1Param(Value:integer);
  {$ELSE}
  procedure M_1Param(Value:integer=0);
  {$ENDIF}
  end;
  constructor TC.Create;
  {$IFDEF DEFAULT_VALUE}
  var M : TMethod;
  {$ENDIF}
  begin
  inherited Create;
  F:=142;
  {$IFNDEF DEFAULT_VALUE}
  Hook_M_1Param(M_1Param);
  {$ELSE}
  TMethod_1Param(M):=M_1Param;
  Hook_M_1Param(M);
   {$ENDIF}
  end;
  procedure TC.M_1Param(Value:integer);
  begin
  writeln('M_1Param called with Value:',Value,' and F is:',F);
  end;
var
  C : TC;
  {$IFDEF DEFAULT_VALUE}
  M : TMethod;
  {$ENDIF}
begin
C:=TC.Create;
{$IFNDEF DEFAULT_VALUE}
writeln('C.Instance:',HexStr(TMethod(TMethod_1Param(C.M_1Param)).Data));
writeln('C.M_1Param:',HexStr(TMethod(TMethod_1Param(C.M_1Param)).Code));
{$ELSE}
// Uncomment the following lines to have a compiler error.
// Illegal type conversion: "untyped" to "<procedure variable type of
procedure(LongInt="0") of object;Register>
//writeln('C.Instance:',HexStr(TMethod(TMethod_1Param(C.M_1Param)).Data));
//writeln('C.M_1Param:',HexStr(TMethod(TMethod_1Param(C.M_1Param)).Code));
// Trick with MethodType casting a Method variable
TMethod_1Param(M):=C.M_1Param;
writeln('C.Instance:',HexStr(M.Data));
writeln('C.M_1Param:',HexStr(M.Code));
{$ENDIF}
end.

Reply by email

Jonas Maebe
to Den Jean
Den Jean wrote 7 lines
So I cannot directly give the hooked procedure as a parameter to a procedure, I have to do stuff like this var M : TMethod TSomeMethodTyp(M):=MyMethod Hook_Signal(M); Instead of Hook_Signal(MyMethod)

That's why in objfpc mode you can (have to) use Hook_Signal(@MyMethod) and everything is unambiguous.

Jonas

Reply by email

Den Jean
to Jonas Maebe
Jonas Maebe wrote
That's why in objfpc mode you can (have to) use Hook_Signal(@MyMethod)

I was rather hoping for an answer/fix for Delphi Mode. May I consider it a bug and file one ?

kind regards,

Den Jean

Reply by email

Jonas Maebe
to Den Jean
Den Jean wrote 5 lines
On Sunday 13 September 2009 22:05:17 Jonas Maebe wrote: > That's why in objfpc mode you can (have to) use Hook_Signal > (@MyMethod) I was rather hoping for an answer/fix for Delphi Mode. May I consider it a bug and file one ?

If the behaviour is different in Delphi.

Jonas

Reply by email

Den Jean
to Jonas Maebe
Jonas Maebe wrote
If the behaviour is different in Delphi.

at least in kylix.

this works in kylix and not in fpc

$ cat hooks2.pas
program hooks;
{$IFDEF FPC}
{$mode delphi}
{$ENDIF}
uses SysUtils,Classes,Types;
{$IFNDEF FPC}
type PtrUInt = DWord; // DCC is 32 bit
function HexStr(P:Pointer) : String;
begin
HexStr:=IntToHex(PtrUInt(P),4);
end;
{$ENDIF}
type
  TMethod_1Param = procedure(Value:integer=0) of object;
  procedure Hook_M_1Param(aMethod: TMethod_1Param);
  begin
  writeln('Hooked: Method.Code:',HexStr(TMethod(aMethod).Data),
          '  Method.Data:',HexStr(TMethod(aMethod).Code));
  TMethod_1Param(aMethod)(143);
  end;
type
  TC = class(TObject)
  public
  F : integer;
  constructor Create;
  procedure M_1Param(Value:integer=0);
  end;
  constructor TC.Create;
  begin
  inherited Create;
  F:=142;
  Hook_M_1Param(M_1Param);
  end;
  procedure TC.M_1Param(Value:integer);
  begin
  writeln('M_1Param called with Value:',Value,' and F is:',F);
  end;
var
  C : TC;
begin
C:=TC.Create;
end.

Reply by email