<div dir="ltr"><div dir="ltr">On Mon, Jul 8, 2019 at 12:04 PM Ryan Joseph <<a href="mailto:genericptr@gmail.com">genericptr@gmail.com</a>> wrote:<br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
There actually is a need to distinguish between getters/setters but the way property syntax works we’re forced for the return type to be the same as the input for the setter. This is a problem I faced before where I want the getter to return a pointer but I want the setter to take a direct value.<br></blockquote><div><br></div><div>One thing I might point out as a general tip is that you don't really necessarily *need* an array-style index for the kind of access you seem to be going for, especially if using something like TValue which has a lot of assignment operator overloads in place by default.</div><div><br></div><div>Here's a little example I threw together:</div><div><br></div><div>program Example;<br><br>{$Mode ObjFPC}{$H+}<br>{$ModeSwitch AdvancedRecords}</div><div>{$ImplicitExceptions Off}</div><div>{$Assertions On}<br><br>uses RTTI;<br><br>  operator :=(const RHS: TValue): TObject; inline;<br>  begin</div><div>    if RHS.IsObject() then<br>      Result := RHS.AsObject()</div><div>    else</div><div>      Result := nil;<br>  end;<br><br>type<br>  TMyClass = class end;<br><br>  TMyRecord = record<br>  strict private<br>    FValue: TValue;<br>  public<br>    procedure FreeIfNecessary; inline;<br>  private<br>    function GetValue: TValue; inline;<br>    procedure SetValue(const V: TValue); inline;<br>  public<br>    property Value: TValue read GetValue write SetValue;<br>  end;<br><br>  procedure TMyRecord.FreeIfNecessary;<br>  var O: TObject = nil;<br>  begin<br>    // Unfortunate misnomer.. IsObject() really returns true if<br>    // the value is a class instance, while IsClass()<br>    // returns true if the value is a class reference.<br>    // Ironically, there is no function for actual TP-style objects.<br>    if FValue.IsObject() then<br>    begin<br>      O := FValue.AsObject();<br>      if O <> nil then<br>        O.Free();<br>    end;<br>  end;<br><br>  function TMyRecord.GetValue: TValue;<br>  begin<br>    case FValue.Kind of<br>      tkSString: Result := FValue.AsString();<br>      tkAString: Result := FValue.AsAnsiString();<br>      tkUString: Result := FValue.AsUnicodeString();<br>      tkFloat: Result := FValue.AsExtended();<br>      tkInteger, tkInt64: Result := FValue.AsOrdinal();<br>      tkQWord: Result := FValue.AsUInt64();<br>      tkBool: Result := FValue.AsBoolean();<br>      tkClass: Result := FValue.AsObject();<br>      else<br>        Assert(False, 'Unsupported data type!');<br>    end;<br>  end;<br><br>  procedure TMyRecord.SetValue(const V: TValue);<br>  begin<br>    FValue := V;<br>  end;<br><br>var<br>  V: TMyRecord;<br>  C: TObject = nil;<br><br>begin<br>  V.Value := 2;<br>  V.Value := 'Hey';<br>  V.Value := 14.567;<br>  V.Value := False;<br>  V.Value := TObject.Create();<br>  V.FreeIfNecessary();<br>  V.Value := TMyClass.Create();<br>  C := V.Value;<br>  WriteLn(C.ClassName());<br>  V.FreeIfNecessary();<br>end.<br></div></div></div>