Recent

Author Topic: Assigning a static class methods to regular procedural variables  (Read 5977 times)

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11455
  • FPC developer.
Re: Assigning a static class methods to regular procedural variables
« Reply #15 on: January 11, 2023, 07:47:29 pm »
As Thaddy says, you have to consider how a callback is called. A compiler is no magic thing, it must work with what information it has, and then document the allowable transitions.

There a couple of options:

  • Straight procedure function, no hidden parameters
  • Straight method, virtual or otherwise. Receives "self" aka the object instance as the hidden parameters
  • class method. Receives a point to the class type-descriptor as parameter. 
  • class static methods, as class method, minus the type descriptor. So effectively compatible with procedure

If you mix in e.g. calling conventions (register, stdcall and cdecl etc), default parameters, overloading etc, and you can imagine why the so called call-node that handles calling an procedure/method/whatever one of the more complex parts of the compiler :-)

« Last Edit: January 11, 2023, 08:36:08 pm by marcov »

simone

  • Hero Member
  • *****
  • Posts: 573
Re: Assigning a static class methods to regular procedural variables
« Reply #16 on: January 11, 2023, 08:15:24 pm »
Thank you so much for discussing the full case study. Considering the implementation aspects illustrated, everything is clear to me now.
Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

simone

  • Hero Member
  • *****
  • Posts: 573
Re: Assigning a static class methods to regular procedural variables
« Reply #17 on: January 12, 2023, 01:26:21 pm »
As a final reflection, hoping not to abuse your courtesy, consider the following program:

Code: Pascal  [Select][+][-]
  1. program Project1;
  2. {$Mode ObjFpc}
  3. type
  4.   TMethodProcedure=procedure of object;
  5.  
  6.   TMyClass=class
  7.     class procedure ProcInClass;
  8.   end;
  9.  
  10. var
  11.   V : TMethodProcedure;
  12.  
  13.   procedure Proc (P : TMethodProcedure);
  14.   begin
  15.  
  16.   end;
  17.  
  18. class procedure TMyClass.ProcInClass;
  19. begin
  20.  
  21. end;
  22.  
  23. begin
  24.   V:=@TMyClass.ProcInClass;      //OK
  25.   Proc(@TMyClass.ProcInClass);   //ERROR
  26. end.  

From how the compiler behaves, it emerges that:

- I can assign a class method to a (type compatible) variable;

- I can't pass a class method as a (type compatible) parameter to a procedure.

Is this an expected behavior? Thanks.
« Last Edit: January 12, 2023, 01:28:58 pm by simone »
Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11455
  • FPC developer.
Re: Assigning a static class methods to regular procedural variables
« Reply #18 on: January 12, 2023, 02:20:07 pm »
That's one for PascalDragon I guess. I'd say not.

simone

  • Hero Member
  • *****
  • Posts: 573
Re: Assigning a static class methods to regular procedural variables
« Reply #19 on: January 12, 2023, 02:42:41 pm »
I remembered that when I started this thread years ago there was something that was not clear to me. Now I have better focused what does not convince me. I will wait the authoritative opinion of PascalDragon. Thanks a lot again.
Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

Thaddy

  • Hero Member
  • *****
  • Posts: 14377
  • Sensorship about opinions does not belong here.
Re: Assigning a static class methods to regular procedural variables
« Reply #20 on: January 12, 2023, 02:59:20 pm »
@Simone
There a glitch in your code, it should be
Code: Pascal  [Select][+][-]
  1. class procedure TMyClass.ProcInClass;static; // static is important here
  2. begin
  3.  // and do not let this get optimized away
  4. end;
See the manuals, again, https://www.freepascal.org/docs-html/ref/refsu30.html first line.

Static class methods have exacly the same signature as a normal procedure or function.
They are also not limited to TProc and TFunc. They can be parameterized too.
« Last Edit: January 12, 2023, 03:05:35 pm by Thaddy »
Object Pascal programmers should get rid of their "component fetish" especially with the non-visuals.

simone

  • Hero Member
  • *****
  • Posts: 573
Re: Assigning a static class methods to regular procedural variables
« Reply #21 on: January 12, 2023, 03:22:30 pm »
Thaddy I read the manual. My question is different. I just want to understand if the compiler behavior in my last example is correct. Like Marcov, I think not.
« Last Edit: January 12, 2023, 03:38:05 pm by simone »
Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

bytebites

  • Hero Member
  • *****
  • Posts: 642
Re: Assigning a static class methods to regular procedural variables
« Reply #22 on: January 12, 2023, 03:24:16 pm »
Add static and get ¨
Quote
project1.lpr(25,29) Error: Incompatible type for arg no. 1: Got "<class method type of procedure of object;Register>", expected "<procedure variable type of procedure of object;Register>"

Without static result is
Quote
project1.lpr(25,3) Error: Internal error 200408162

Thaddy

  • Hero Member
  • *****
  • Posts: 14377
  • Sensorship about opinions does not belong here.
Re: Assigning a static class methods to regular procedural variables
« Reply #23 on: January 12, 2023, 03:38:04 pm »
TMethod procedure is not compatible with static class procedure. It is simply a procedure:
Type TMyProcedure = procedure;
Object Pascal programmers should get rid of their "component fetish" especially with the non-visuals.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5486
  • Compiler Developer
Re: Assigning a static class methods to regular procedural variables
« Reply #24 on: January 12, 2023, 11:00:59 pm »
Is this an expected behavior? Thanks.

That's a bug (cause it compiles in mode Delphi with the @s removed). However it compiles with 3.3.1, so it's been fixed in the meantime. If someone bisects the commit that fixed it between 3.2.0 and current head then I might be able to merge it to 3.2.3.

Add static and get ¨
Quote
project1.lpr(25,29) Error: Incompatible type for arg no. 1: Got "<class method type of procedure of object;Register>", expected "<procedure variable type of procedure of object;Register>"

The compiler should probably add a “static” to the method description to make the issue clearer... ::)

Without static result is
Quote
project1.lpr(25,3) Error: Internal error 200408162

What platform? What compiler version? I don't get an internal error on x86_64-win64 with 3.2.2, only the compile error that simone got. And no error at all with 3.3.1.

simone

  • Hero Member
  • *****
  • Posts: 573
Re: Assigning a static class methods to regular procedural variables
« Reply #25 on: January 12, 2023, 11:35:43 pm »
Is this an expected behavior? Thanks.

That's a bug (cause it compiles in mode Delphi with the @s removed). However it compiles with 3.3.1, so it's been fixed in the meantime. If someone bisects the commit that fixed it between 3.2.0 and current head then I might be able to merge it to 3.2.3.

Thank you PascalDragon and Marcov for your kind and qualified answers, as always.

Microsoft Windows 10 64 bit - Lazarus 3.0 FPC 3.2.2 x86_64-win64-win32/win64

bytebites

  • Hero Member
  • *****
  • Posts: 642
Re: Assigning a static class methods to regular procedural variables
« Reply #26 on: January 13, 2023, 10:19:25 am »
Linux 64-bit version 3.3.1

Thaddy

  • Hero Member
  • *****
  • Posts: 14377
  • Sensorship about opinions does not belong here.
Re: Assigning a static class methods to regular procedural variables
« Reply #27 on: January 13, 2023, 03:09:59 pm »
In trunk/main this is very easy to achieve, btw - and less error prone - by using function references
Example:
Code: Pascal  [Select][+][-]
  1. {$ifdef mswindows}{$apptype console}{$endif}
  2. {$mode delphi}
  3. {$modeswitch functionreferences}
  4. {$modeswitch anonymousfunctions}
  5. {$macro on}
  6. {$if FPC_FULLVERSION<30301}{$ERROR this code needs FPC version 3.3.1 later than May 28, 2022 or higher}{$ifend}
  7.  
  8. uses
  9.   SysUtils;
  10.  
  11. type
  12.   TTestProc = procedure(X: Integer);
  13.   TTestMeth = procedure(X: Integer) of object;
  14.   TTestRef = reference to procedure(X: Integer);
  15.  
  16. // Ordinary procedure
  17. procedure TestProc(X: Integer);
  18. begin
  19.   writeln('Ordinary: '#9,X);
  20. end;
  21.  
  22. // Method
  23. type
  24.   TMyClass = class
  25.     class procedure TestMeth(X: Integer);
  26.   end;
  27.  
  28. class procedure TMyClass.TestMeth(X: Integer);
  29. begin
  30.   writeln('Method: '#9,X);
  31. end;
  32.  
  33. {
  34. The reference to X can be:
  35. 1. X
  36. 2. class method X of object (must be class method)
  37. 3. reference to X, where X is a procedural type such as procedure(X: Integer).
  38.  
  39. The references are assignment compatible
  40. }
  41. var
  42.   A,B: TTestRef;
  43. begin
  44.   A := TestProc;
  45.   A(1);
  46.   A := TMyClass.TestMeth;
  47.   A(2);
  48.   // test assignment compatibility
  49.   B:=A;
  50.   A := procedure(X: Integer)
  51.        begin
  52.          writeln('Anonymous: '#9,X);
  53.        end;
  54.   A(3);
  55.   B(4);
  56. end.

In the case of a class, this will refuse a normal method of a class, it will only accept class methods.
This is also Delphi compatible.
« Last Edit: January 14, 2023, 07:02:31 pm by Thaddy »
Object Pascal programmers should get rid of their "component fetish" especially with the non-visuals.

 

TinyPortal © 2005-2018