Saturday, June 24, 2006

Compiler-generated getters and setters

(Sorry, not today. Maybe in a not-too-distant future.)

A very common task when implementing interfaces is writing getter and setter methods. In many cases, getters only access internal fields. In some cases, even setters only access internal fields. Still, we have to code those pesky methods by hand (or in a slightly simpler way using great ModelMaker Code Explorer - oh I like it so much!). I think that Delphi compiler could lend us a hand here and automatically generate trivial accessors when needed.

Let’s take a look at the example:

type
ISimpleInterface = interface
function GetProp1: integer;
procedure SetProp1(value: integer);
property Prop1: integer read GetProp1 write SetProp1;
end;
TSimpleObject = class(TInterfacedObject, ISimpleInterface)
private
FProp1: integer;
public
function GetProp1: integer;
procedure SetProp1(value: integer);
end;
{ TSimpleObject }
function TSimpleObject.GetProp1: integer;
begin
Result := FProp1;
end;
procedure TSimpleObject.SetProp1(value: integer);
begin
FProp1 := value;
end;

Even though we only want to implement the Prop1 property using direct access to a field, we still have to write two very dull methods.

We should be able to tell the compiler to do that for us. It is quite obvious that the compiler has enough data (it already knows the getter/setter signatures from the interface declaration) to generate both methods. The main question is how to instruct it to do so.

At the beginning I intended to abuse the ‘automated’ keyword (as it is already tokenized by the parser) like so:
TSimpleObject = class(TInterfacedObject, ISimpleInterface)
private
FProp1: integer
public
property Prop1: integer read GetProp1 automated FProp1 write SetProp1 automated FProp1;
end;

This was not very optimal as it requires you to declare the Prop1 property in the TSimpleObject, which is not requirement per se when implementing interfaces.

Next idea was:
TSimpleObject = class(TInterfacedObject, ISimpleInterface)
private
FProp1: integer;
public
property Prop1: integer read GetProp1 = FProp1 write SetProp1 = FProp1;
end;

It doesn’t abuse the ‘automated’ keyword but carries same problems.

My current favorite, suggested by a fellow programmer Lee_Nover, uses same syntax as method aliasing:
TSimpleObject = class(TInterfacedObject, ISimpleInterface)
private
FProp1: integer;
public
function ISimpleInterface.GetProp1 = FProp1;
procedure ISimpleInterface.SetProp1 = FProp1;
end;

Although this syntax is very clear and self-describing, I would prefer to see a following simplified form:
TSimpleObject = class(TInterfacedObject, ISimpleInterface)
private
FProp1: integer;
public
function GetProp1 = FProp1;
procedure SetProp1 = FProp1;
end;

So, dear reader, what do you think? If you like the suggestion, open QC #30533 and vote for it.

1 comment:

  1. Well, you could create a procedure and function of object that serves for all properties.
    Type
    TSetValue: procedure(prop: variant) of object;

    ReplyDelete