- refactoring may break your code
- typos may break your code
- no possible compiler checks for correctness
- no code completion support
typeAs you also may know this is a reference counted type. Guess how it is implemented? Correct, with an interface. This is similar to:
TFunc<T> = reference to function: T;
typeYou can even use those method reference types as Interface when you implement a class:
IFunc<T> = interface
function Invoke(): T;
end;
typeOr you can inherit your interface from it (and of course implement that interface into your class):
TMyFuncClass = class(TInterfacedObject, TFunc<Integer>)
public
function Invoke: Integer;
end;
typeOk, but we were talking about properties, right? Well a property basically is not much more than the combination of a function and a procedure - the getter and the setter.
IFunc<T> = interface(TFunc<T>)
end;
We could define it like this:
typeSo it is nothing more than (of course this does not work):
IProp<T> = interface
function GetValue: T;
procedure SetValue(Value: string);
property Value: T read GetValue write SetValue;
end;
typeBut what you can do is this:
IProp<T> = interface(TFunc<T>, TProc<T>)
property Value: T read Invoke write Invoke;
end;
typeWe can take this and use it as property reference passing it around, getting and setting values using RTTI but there we are again, how to create an instance? Yes, specifying the instance and the property by string. Another possibility would be with anonymous methods wrapping the property.
TProp<T> = class(TInterfacedObject, TFunc<T>, TProc<T>)
private
function Invoke: T; overload;
procedure Invoke(Value: T); overload;
public
property Value: T read Invoke write Invoke;
end;
How about some built in type like this?
typeSo I could write something like this:
TProp<T> = reference to property: T;
procedure ShowAndInc(AProp: TProp<NativeInt>);
begin
ShowMessageFmt('%d', [AProp]);
AProp := AProp + 1;
end;
procedure Form1Button1Click(Sender: TObject);
begin
ShowAndInc(Self.Tag);
end;
What the compiler actually needs to do is something like this (ignoring possible read or write only properties for now):
ShowAndInc(TProp<NativeInt>.Create(This is the code of my actual working TProp class and interface:
function: NativeInt
begin
Result := Self.Tag;
end,
procedure(Value: NativeInt)
begin
Self.Tag := Value;
end));
typeThe compiler could do it way better by directly putting the call to the getter and setter into the right places.
IProp<T> = interface
function Invoke: T; overload;
procedure Invoke(Value: T); overload;
property Value: T read Invoke write Invoke;
end;
TProp<T> = class(TInterfacedObject, IProp<T>)
private
FGetter: TFunc<T>;
FSetter: TProc<T>;
function Invoke: T; overload;
procedure Invoke(Value: T); overload;
public
constructor Create(Getter: TFunc<T>; Setter: TProc<T>);
property Value: T read Invoke write Invoke;
end;
{ TProp<T> }
constructor TProp<T>.Create(Getter: TFunc<T>; Setter: TProc<T>);
begin
FGetter := Getter;
FSetter := Setter;
end;
function TProp<T>.Invoke: T;
begin
Result := FGetter;
end;
procedure TProp<T>.Invoke(Value: T);
begin
FSetter(Value);
end;
So what do you think? Do you want reference to property in one of the next Delphi versions? Any drawbacks I am not seeing right now?