Properties are "virtual fields" that provide controlled access to object data. They can map directly to a field or use getter and setter methods to implement logic when a value is accessed or modified.
A property is declared with a read and/or write specifier.
type
TUser = class
private
FName: String;
FAge: Integer;
procedure SetAge(Value: Integer);
begin
if Value < 0 then raise new Exception('Age cannot be negative');
FAge := Value;
end;
public
property Name: String read FName write FName;
property Age: Integer read FAge write SetAge;
end; You can create read-only or write-only properties by omitting one of the specifiers:
type
TExample = class
private
FSecret: String;
public
property Secret: String read FSecret;
end; If you omit the read and write clauses, DWScript will automatically generate a backing field for the property. This reduces boilerplate code for simple data containers.
type
TUser = class
// Automatically creates a private field and getter/setter
property Name: String;
// You can mix auto-implemented properties with standard ones
property Age: Integer;
// Also works for class properties (static fields)
class property Count: Integer;
end;
var u := new TUser;
u.Name := 'Bob';
TUser.Count := 1; Array properties allow you to access data using an index, mimicking array syntax (obj[index]).
type
TStringList = class
private
FItems: array of String;
function GetItem(index: Integer): String;
begin
Result := FItems[index];
end;
procedure SetItem(index: Integer; value: String);
begin
FItems[index] := value;
end;
public
property Items[index: Integer]: String read GetItem write SetItem;
end; If an array property is marked as default, you can omit the property name when accessing it.
type
TMyContainer = class
public
function GetItem(index: Integer): String;
begin
Result := 'Item ' + IntToStr(index);
end;
property Items[index: Integer]: String read GetItem; default;
end;
var list := TMyContainer.Create;
PrintLn(list[0]); Item 0
Indexed properties allow multiple properties to share the same getter or setter by passing a constant index value to the accessor.
type
TSensor = class
private
function GetValue(index: Integer): Float;
begin
case index of
0: Result := 22.5;
1: Result := 45.0;
else
Result := 0.0;
end;
end;
public
property Temperature: Float index 0 read GetValue;
property Humidity: Float index 1 read GetValue;
end;
var s := TSensor.Create;
PrintLn(FloatToStr(s.Temperature)); 22.5
Class properties allow you to access a property directly through the class type without an instance. They must use class methods or class fields as their accessors.
type
TSystem = class
class function GetVersion: String;
begin
Result := '1.0.0';
end;
class property Version: String read GetVersion;
end;
PrintLn(TSystem.Version); 1.0.0
DWScript allows you to define properties using expressions directly in the declaration, avoiding the need for boilerplate getter or setter functions. Expressions must be enclosed in parentheses.
type
TCircle = class
Radius : Float;
// Read expression
property Diameter : Float read (Radius * 2);
// Read and write expressions
property Area : Float
read (PI * Sqr(Radius))
write (Radius := Sqrt(Value / PI));
end;
var c := new TCircle;
c.Radius := 5;
PrintLn(c.Diameter.ToString);
c.Area := 100;
PrintLn(c.Radius.ToString); 10 5.64189583547756
Subclasses can redeclare a property from a parent class to change its visibility (e.g., from protected to public) or to provide a new implementation.
type
TBase = class
private
FValue : Integer;
protected
property Value: Integer read FValue;
end;
type
TSub = class(TBase)
public
property Value;
end;