Recent

Author Topic: Method of Field as getter/setter for property  (Read 4389 times)

soerensen3

  • Full Member
  • ***
  • Posts: 213
Method of Field as getter/setter for property
« on: July 23, 2018, 12:42:52 pm »
I'm trying to simplify declaring properties with my smart pointer class and I remember there was some way you could access a method of a field and use it for a getter or setter of another class containing this field. It might become more clear if you look at this code.

Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. uses
  4.   Classes;
  5.  
  6. type
  7.  
  8.   generic ITestProp < T: TObject > = interface
  9.     ['{B0585610-BE1D-449E-A5D7-08E6DA9A3692}']
  10.     function GetTestProp: T;
  11.     procedure SetTestProp(AValue: T);
  12.   end;
  13.  
  14.   { TTestProp }
  15.  
  16.   generic TTestProp < T: TObject > = class ( TInterfacedPersistent, specialize ITestProp < T > )
  17.     published
  18.       function GetTestProp: T;
  19.       procedure SetTestProp(AValue: T);
  20.       property TestProp: T read GetTestProp write SetTestProp;
  21.   end;
  22.  
  23.   TClass1 = class            
  24.   end;
  25.  
  26.   TClass2 = class
  27.     protected
  28.       FTestProp: specialize TTestProp < TClass1 >;
  29.       FITestProp: specialize ITestProp < TClass1 >;
  30.  
  31.     public // Both of these property definitions do not work at the moment.
  32.       property Prop: TClass1 read FTestProp.GetTestProp write FTestProp.SetTestProp; // Declaring the property without an interface
  33.       property Prop2: TClass1 read FITestProp.GetTestProp write FITestProp.SetTestProp; // Declaring the property with an interface
  34.   end;
  35.  
  36. { TTestProp }
  37.  
  38. function TTestProp.GetTestProp: T;
  39. begin
  40.  
  41. end;
  42.  
  43. procedure TTestProp.SetTestProp(AValue: T);
  44. begin
  45.  
  46. end;
  47.  
  48. begin
  49. end.
  50.  
With both property declarations I get an error like this: "project1.lpr(59,45) Error: Unknown record field identifier "GetTestProp"" (For all getters and setters). It doesn't help using a record instead of a class for the field. Was this feature removed or do I do anything wrong? I couldn't find it in the docs either.

« Last Edit: July 23, 2018, 01:09:44 pm by soerensen3 »
Lazarus 1.9 with FPC 3.0.4
Target: Manjaro Linux 64 Bit (4.9.68-1-MANJARO)

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9792
  • Debugger - SynEdit - and more
    • wiki
Re: Method of Field as getter/setter for property
« Reply #1 on: July 23, 2018, 12:50:36 pm »
This only works, if the field (FTestProp) is of type record.


soerensen3

  • Full Member
  • ***
  • Posts: 213
Re: Method of Field as getter/setter for property
« Reply #2 on: July 23, 2018, 01:07:19 pm »
Unfortunately not even then:

Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. {$modeswitch ADVANCEDRECORDS}
  4.  
  5. uses
  6.   Classes;
  7.  
  8. type
  9.   { TTestProp }
  10.  
  11.   generic TTestProp < T: TObject > = record
  12.     function GetTestProp: T;
  13.     procedure SetTestProp(AValue: T);
  14.     property TestProp: T read GetTestProp write SetTestProp;
  15.   end;
  16.  
  17.   TClass1 = class
  18.   end;
  19.  
  20.   TClass2 = class
  21.     protected
  22.       FTestProp: specialize TTestProp < TClass1 >;
  23.  
  24.     public
  25.       property Prop: TClass1 read FTestProp.GetTestProp write FTestProp.SetTestProp; // Declaring the property without an interface
  26.   end;
  27.  
  28. { TTestProp }
  29.  
  30. function TTestProp.GetTestProp: T;
  31. begin
  32.  
  33. end;
  34.  
  35. procedure TTestProp.SetTestProp(AValue: T);
  36. begin
  37.  
  38. end;
  39.  
  40. begin
  41. end.
  42.  
« Last Edit: July 23, 2018, 01:10:10 pm by soerensen3 »
Lazarus 1.9 with FPC 3.0.4
Target: Manjaro Linux 64 Bit (4.9.68-1-MANJARO)

soerensen3

  • Full Member
  • ***
  • Posts: 213
Re: Method of Field as getter/setter for property
« Reply #3 on: July 23, 2018, 01:14:14 pm »
What however works is:
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. {$modeswitch ADVANCEDRECORDS}
  4.  
  5. uses
  6.   Classes;
  7.  
  8. type
  9.   { TTestProp }
  10.  
  11.   generic TTestProp < T: TObject > = record
  12.     FTestProp: T;
  13.     property TestProp: T read FTestProp write FTestProp;
  14.   end;
  15.  
  16.   TClass1 = class
  17.   end;
  18.  
  19.   TClass2 = class
  20.     protected
  21.       FTestProp: specialize TTestProp < TClass1 >;
  22.  
  23.     public
  24.       property Prop: TClass1 read FTestProp.FTestProp write FTestProp.FTestProp; // Declaring the property without an interface
  25.   end;
  26.  
  27.  
  28. begin
  29. end.
  30.  
But not with methods. I thought I've seen it with methods before (Maybe in combination with interfaces? But I tried that as well, see the original example). I might be wrong though..
Lazarus 1.9 with FPC 3.0.4
Target: Manjaro Linux 64 Bit (4.9.68-1-MANJARO)

Thaddy

  • Hero Member
  • *****
  • Posts: 14204
  • Probably until I exterminate Putin.
Re: Method of Field as getter/setter for property
« Reply #4 on: July 23, 2018, 02:09:19 pm »
Was this feature removed or do I do anything wrong? I couldn't find it in the docs either.
It was never a feature in the first place, at least out of the box.
But there is something like the MakeMethod function from KOL - which I happened to co-write  :P :P 8-)  - that takes a normal procedure or function with a dummy parameter and makes it into a method.
I will add an example later. Works also for Lazarus. Works also on arm.
Code: Pascal  [Select][+][-]
  1. {$ifdef fpc}{$mode delphi}{$H+}{$endif}
  2. uses classes;
  3. type
  4.   TNotifyFunc = function(sender:Tobject):integer of object;
  5.  
  6.   function readVar(dummy:pointer;sender:Tobject):integer;forward;
  7.   function MakeMethod( Data, Code: Pointer ): TMethod;forward;
  8.  
  9. type
  10.   TMyClass = class
  11.   private
  12.     FField:Integer;
  13.     FEvent:TNotifyFunc;
  14.   public
  15.     constructor create;
  16.     Property Someproperty:TNotifyFunc read Fevent;
  17.   end;
  18.  
  19.   constructor TMyClass.Create;
  20.   begin
  21.     inherited create;
  22.     Fevent := TNotifyFunc(MakeMethod(@self,@Readvar));
  23.     FField := 100;
  24.   end;
  25.      
  26. {* Help function to construct TMethod record. Can be useful to
  27.       assign regular type procedure/function as event handler for
  28.       event, defined as object method (do not forget, that in that
  29.       case it must have first dummy parameter to replace @Self,
  30.       passed in EAX/RAX to methods of object). }
  31.  
  32. function MakeMethod( Data, Code: Pointer ): TMethod;
  33. begin
  34.   Result.Data := Data;
  35.   Result.Code := Code;
  36. end;
  37.  
  38. function readVar(dummy:pointer;sender:Tobject):integer;
  39. begin
  40.   Result := TMyClass(sender).FField;
  41. end;
  42.  
  43. var
  44.   test:TMyClass;
  45. begin
  46.   test := TMyClass.Create;
  47.   writeln(Test.Someproperty(test));
  48.   test.free;
  49. end.

Quite a bit of hackery but possible.
« Last Edit: July 23, 2018, 03:47:01 pm by Thaddy »
Specialize a type, not a var.

soerensen3

  • Full Member
  • ***
  • Posts: 213
Re: Method of Field as getter/setter for property
« Reply #5 on: July 23, 2018, 05:35:15 pm »
Hi Thaddy,

I'm not sure if this will solve my problem but it definitely looks interesting.

However my idea was to make it simpler to define a property of my smart pointer class. When declaring a property like from the sample before it currently requires me to write a getter/setter for every property (Indexing helps a little). I could of course access the field directly or declare the field in  TTestClass2 but I also need to track changes so there is no help but using at least a setter. If I your method requires to declare a getter or setter in TTestClass2 it's the kind of the same as before or did you mean something else.
Lazarus 1.9 with FPC 3.0.4
Target: Manjaro Linux 64 Bit (4.9.68-1-MANJARO)

Thaddy

  • Hero Member
  • *****
  • Posts: 14204
  • Probably until I exterminate Putin.
Re: Method of Field as getter/setter for property
« Reply #6 on: July 23, 2018, 05:54:14 pm »
Hi Thaddy,

I'm not sure if this will solve my problem but it definitely looks interesting.

However my idea was to make it simpler to define a property of my smart pointer class. When declaring a property like from the sample before it currently requires me to write a getter/setter for every property (Indexing helps a little). I could of course access the field directly or declare the field in  TTestClass2 but I also need to track changes so there is no help but using at least a setter. If I your method requires to declare a getter or setter in TTestClass2 it's the kind of the same as before or did you mean something else.
Have you seen my smartpointer class? That works. http://forum.lazarus.freepascal.org/index.php/topic,39257.msg270350.html#msg270350
Specialize a type, not a var.

ASerge

  • Hero Member
  • *****
  • Posts: 2222
Re: Method of Field as getter/setter for property
« Reply #7 on: July 23, 2018, 08:15:47 pm »
Was this feature removed or do I do anything wrong? I couldn't find it in the docs either.
Property getters and setters are methods or fields. Fields are either immediately a name or a name inside a complex structure, but whose offset from the beginning of Self is known at compile time. And methods are methods of the class itself.
For example, fields:
Code: Pascal  [Select][+][-]
  1. type
  2.   T = class(TObject)
  3.   private
  4.     FA: array[0..3] of Integer;
  5.     FR: record
  6.       X: Integer;
  7.     end;
  8.   public
  9.     property A: Integer read FA[0] write FA[1];
  10.     property B: Integer read FR.X write FA[2];
  11.   end;

soerensen3

  • Full Member
  • ***
  • Posts: 213
Re: Method of Field as getter/setter for property
« Reply #8 on: July 23, 2018, 11:47:53 pm »
@ASerge: So this is kind of what my test showed. So this is a dead end. Thanks for clarification

@Thaddy: Yes that looks familiar. The implicit operator could indeed be the solution if I didn't have to use inheritance (thus classes) for my own property class (The implicit operator only works for records as far as I know). I recreated some kind of RTTI with some special functionality for my engine. My smart pointer is a descendant of the property. But thinking about it again it would be a lot better if I decoupled the smart pointer from the property class. I will look into it again some time later. Thanks for pointing this out!

Lazarus 1.9 with FPC 3.0.4
Target: Manjaro Linux 64 Bit (4.9.68-1-MANJARO)

 

TinyPortal © 2005-2018