March 25, 2013

New in Smart 1.1: Property Expression

Smart Pascal supports properties just the same as Delphi and Free Pascal do. Properties are supported in classes, records, interfaces and in helpers (helper classes and records). In addition to the standard syntax, Smart Pascal supports property expressions which help you write more compact code.

Property expressions can be used in two ways – by providing a backing storage (typically a field or property containing the data) or by providing a modifying expression (an expression that modifies and returns/stores data). In both cases, property expressions are introduced by an opening parenthesis and ended by a closing parenthesis.

The simplest way to explain the functioning of this language extension is through examples. The following example defines a form containing two labels, W3lblTask and W3lblDetail. The form also defines two properties. Property Task provides access to the W3lblTask.Caption and property Detail provides access to the W3lblDetail.Caption.

type
TToDoListTemplate=class
(TW3form)
private
{$I 'ToDoListTemplate:intf'}
protected
procedure InitializeObject; override
;
public
property Task: string read
(W3lblTask.Caption) write (W3lblTask.Caption);
property Detail: string read
(W3lblDetail.Caption) write (W3lblDetail.Caption);
end
;

Equivalent code in a “classic” style would be quite longer.

type
TToDoListTemplate=class
(TW3form)
private
{$I 'ToDoListTemplate:intf'}
function GetDetail: string
;
function GetTask: string
;
procedure SetDetail(value: string
);
procedure SetTask(value: string
);
protected
procedure InitializeObject; override
;
public
property Task: string read GetTask write
SetTask;
property Detail: string read GetDetail write
SetDetail;
end
;

function TToDoListTemplate.GetDetail: string
;
begin
Result :=
W3lblDetail.Caption;
end
;

function TToDoListTemplate.GetTask: string
;
begin
Result :=
W3lblTask.Caption;
end
;

procedure TToDoListTemplate.SetDetail(value: string
);
begin
W3lblDetail.Caption :=
value;
end
;

procedure TToDoListTemplate.SetTask(value: string
);
begin
W3lblTask.Caption :=
value;
end
;

In the example above, (W3lblTask.Caption) and (W3lblDetail.Caption) provide a backing storage; a place where the data is stored. We can, however, do more and write a full expression inside the property expression-wrapping brackets. In case of a getter (read access) this expression must return a result and in case of the setter (write access) this expression should be a statement setting the value of the property. The setter can use a pseudo-parameter Value holding the value that was assigned to the property in the code.

I've said should be a statement because the compiler is not really fussy and will handle any expression in the setter. This allows for weird tricks where the assignment to a property produces a side effect.

The second example defines a TAngle record which holds one value (angle) stored in radians and exposes it through two properties, Radians returning the value in radians and Degrees returning the value in degrees. Conversion between radians and degrees is done inside property expressions.

type
TAngle =
record
FAngleRad:
float;
property Radians: float read FAngleRad write
FAngleRad;
property Degrees: float read (Radians/Pi*180
) write (Radians := Value/180*Pi);
end
;

Equivalent code in “classic” style would again be longer.

type
TAngle =
record
FAngleRad:
float;
functon GetDegrees:
float;
procedure SetDegrees(Value:
float);
property Radians: float read FAngleRad write
FAngleRad;
property Degrees: float read GetDegrees write
SetDegrees;
end
;

function TAngle.GetDegrees:
float;
begin
Result := Radians/Pi*180
;
end
;

procedure TAngle.SetDegrees(Value:
float);
begin
Radians := Value/180
*Pi;
end
;

No comments:

Post a Comment