delphidwscript

DWScript setter for a property which is a Record


my issue is pretty simple. I have a dwsUnit which have this code:

type
  TPointCoord = record
    X: Float;
    Y: Float;
    Z: Float;
  end;

type
  TMyClass = class
  private
    fPosition: TPointCoord;

    function GetPosition: TPointCoord;
    procedure SetPosition(Val: TPointCoord);
  public
    property Position: TPointCoord read GetPosition write SetPosition;
    constructor Create;
end;

function TMyClass.GetPosition: TPointCoord;
begin
  Result := fPosition;
end;

procedure TMyClass.SetPosition(Val: TPointCoord);
begin
  fPosition := Val;
end;

constructor TMyClass.Create;
begin
  inherited Create;
  fPosition.X := 1;
  fPosition.Y := 2;  
  fPosition.Z := 3;    
end;

var
  mc: TMyClass;
begin
  mc := TMyClass.Create;
  mc.Position.X := 2;   //Syntax Error
end.

At mc.Position.X (or Position.Y or Z) i get:

Syntax Error: Cannot assign a value to the left-side argument [line: 42, column: 17]

What is the meaning of this? Is Record read-only if is a property? And how I can access that from Delphi Side. (the second issue, not a really big deal)


Solution

  • The reason for this error is because you're using a property of type record.

    Record type is a value type, which means it's copied on assignment rather than referenced (like a class), so a function (or property) returning a record will make a copy and return a different record.

    So your line

    mc.Position.X := 2
    

    is effectively equivalent to

    temp := mc.getPosition;
    temp.X := 2;
    

    with "temp" being a different variable/storage from fPosition, so that code wouldn't change fPosition.X, it would only the "hidden" temporary copy's X field.

    As this is generally unlikely to be what you're after, the DWS compiler, just like Delphi, throws an error.

    The typical solution is to offer a distinct PositionX property, which will provide access to the X field of fPosition like

    property PositionX : TPointCoord read (FPosition.X) write (FPosition.X);
    

    or you can use explicit getters/setters, if you need more than the X field assigned.

    Another solution would be use a reference types (a class f.i.), though this may not be very practical for a position or coordinate.