<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>