[fpc-devel] [] property overloads

Ben Grasset operator97 at gmail.com
Mon Jul 8 20:16:52 CEST 2019


On Mon, Jul 8, 2019 at 12:04 PM Ryan Joseph <genericptr at gmail.com> wrote:

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

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.

Here's a little example I threw together:

program Example;

{$Mode ObjFPC}{$H+}
{$ModeSwitch AdvancedRecords}
{$ImplicitExceptions Off}
{$Assertions On}

uses RTTI;

  operator :=(const RHS: TValue): TObject; inline;
  begin
    if RHS.IsObject() then
      Result := RHS.AsObject()
    else
      Result := nil;
  end;

type
  TMyClass = class end;

  TMyRecord = record
  strict private
    FValue: TValue;
  public
    procedure FreeIfNecessary; inline;
  private
    function GetValue: TValue; inline;
    procedure SetValue(const V: TValue); inline;
  public
    property Value: TValue read GetValue write SetValue;
  end;

  procedure TMyRecord.FreeIfNecessary;
  var O: TObject = nil;
  begin
    // Unfortunate misnomer.. IsObject() really returns true if
    // the value is a class instance, while IsClass()
    // returns true if the value is a class reference.
    // Ironically, there is no function for actual TP-style objects.
    if FValue.IsObject() then
    begin
      O := FValue.AsObject();
      if O <> nil then
        O.Free();
    end;
  end;

  function TMyRecord.GetValue: TValue;
  begin
    case FValue.Kind of
      tkSString: Result := FValue.AsString();
      tkAString: Result := FValue.AsAnsiString();
      tkUString: Result := FValue.AsUnicodeString();
      tkFloat: Result := FValue.AsExtended();
      tkInteger, tkInt64: Result := FValue.AsOrdinal();
      tkQWord: Result := FValue.AsUInt64();
      tkBool: Result := FValue.AsBoolean();
      tkClass: Result := FValue.AsObject();
      else
        Assert(False, 'Unsupported data type!');
    end;
  end;

  procedure TMyRecord.SetValue(const V: TValue);
  begin
    FValue := V;
  end;

var
  V: TMyRecord;
  C: TObject = nil;

begin
  V.Value := 2;
  V.Value := 'Hey';
  V.Value := 14.567;
  V.Value := False;
  V.Value := TObject.Create();
  V.FreeIfNecessary();
  V.Value := TMyClass.Create();
  C := V.Value;
  WriteLn(C.ClassName());
  V.FreeIfNecessary();
end.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freepascal.org/pipermail/fpc-devel/attachments/20190708/2d5695ba/attachment-0001.html>


More information about the fpc-devel mailing list