Property expressions and statements
Object Pascal does allow binding a property to a field for direct read/writer, but we all have seen properties that required a slightly more complex getter or setter, and that usually meant a method for both. DWScript (svn trunk) & Smart Pascal (1.1) now support property expressions and statements, so the syntax is extended to allow:
property Name : Type read (expression) write (expression|statement)
Under the hood, the compiler will generate an unnamed getter or setter method when appropriate.
Let’s take f.i. a class that exposes an internal list, you can now use just
TMyClass = class private FList : array of TElement; public property Items[i: Integer] : TElement read (FList[i]) write (FList[i]); default; property Count : Integer read (FList.Length); end;
Look Ma! No implementation and no constructor needed for trivial properties!
The astute reader will quickly notice how much shorter this is compared to doing it with a TList<T> and classic properties instead.
And for an hypothetical angle value types that accepts both radians and degrees you could have
TMyAngle = record private FAngle : Float; public property Radians : Float read FAngle write FAngle; property Degrees : Float read (RadToDeg(FAngle)) write (FAngle:=DegToRad(Value)); end;
In the setter statement, there is a special value creatively named… “Value” which holds the value assigned to the property.
In addition to expressions and statements, you can also if specify a property name as getter or setter, this will create an alias (no under-the-hood getter or setter method will be created):
TAncestor = class private FHidden : Integer; procedure SetSecret(v : Integer); protected property Hidden : Integer read FHidden write FHidden; property Secret : Integer write SetSecret; end; TSubClass = class (TAncestor) public property Revealed : Integer read Hidden write Secret; property OldReveal : Integer read Revealed write Revealed; deprecated; end;
Which can be of use when you want to make public a protected property under a different name in a subclass, and the underlying field or method being private wasn’t visible. It can also be helpful if you want to rename a property in a migration-friendly way, with the old name deprecated.
So to summarize:
- read now accepts expressions and properties, in addition to field names and methods names
- write now accepts writable expressions (the left-side of an assignment), statements (an assignment or a method call) and properties in addition to field names and method names. “Value” contains the value assigned to the property.
- property expressions are supported for classes, records, helpers and interfaces.
As we weren’t sure of the potential ambiguity, the compiler currently requires the presence of brackets ( ) before the new expressions and statements are allowed, this requirement might be lifted in the future, or maybe not, as it makes such expressions stand out more.
This is an open question, Oxygen accepts read expressions without brackets (but doesn’t have write expressions or statements), so feedback on this aspect is welcome.
Thanks go to Primoz Gabrielcic for providing the unit tests for the above feature!