Am 26.06.2021 um 00:12 schrieb Ryan Joseph via fpc-pascal:
Is it possible something like this could work? Seems like it should but I get 
an error (got MyRecord expected variant).

====================================

{$mode objfpc}

program unit_name;

type
   TTuple = array of variant;

type
   MyRecord = record
   end;

var
   t: TTuple;
   r: MyRecord;
   i: variant;
begin
   t := [1,'string', r];
   for i in t do
     begin
       writeln(i);
     end;
end.

Variants by themselves can not handle records, because they can't carry type information. However by using TCustomVariantType one can come rather close though one still needs to some things manually:

=== code begin ===

program tvarrec;

{$mode objfpc}{$H+}
{$modeswitch advancedrecords}

uses
  Variants;

type
  generic TRecVariantType<T: record> = class(TCustomVariantType)
  private type
    PT = ^T;
  public
    procedure Copy(var Dest: TVarData; const Source: TVarData;
      const Indirect: Boolean); override;
    procedure Clear(var V: TVarData); override;
    function ToVariant(const aArg: T): Variant;
    function FromVariant(const aArg: Variant): T;
  end;

{ TRecVariantType }

procedure TRecVariantType.Copy(var Dest: TVarData; const Source: TVarData;
  const Indirect: Boolean);
begin
  New(PT(Dest.vrecord));
  PT(Dest.vrecord)^ := PT(Source.vrecord)^;
end;

procedure TRecVariantType.Clear(var V: TVarData);
begin
  Dispose(PT(V.vrecord));
  V.vtype:=varEmpty;
  V.vrecord:=Nil;
end;

function TRecVariantType.ToVariant(const aArg: T): Variant;
begin
  TVarData(Result).vtype := VarType;
  New(PT(TVarData(Result).vrecord));
  PT(TVarData(Result).vrecord)^ := aArg;
end;

function TRecVariantType.FromVariant(const aArg: Variant): T;
begin
  if TVarData(aArg).VType <> VarType then
    EVariantTypeCastError.Create('Not a suitable record');
  Result := PT(TVarData(aArg).vrecord)^;
end;

type
  TMyRec = record
    f: LongInt;
    s: String;
    class operator := (const aOther: TMyRec): Variant;
    class operator := (const aOther: Variant): TMyRec;
  end;

  TMyRecVarType = specialize TRecVariantType<TMyRec>;

var
  myrectype: TMyRecVarType;

{ TMyRec }

class operator TMyRec.:=(const aOther: TMyRec): Variant;
begin
  Result := myrectype.ToVariant(aOther);
end;

class operator TMyRec.:=(const aOther: Variant): TMyRec;
begin
  Result := myrectype.FromVariant(aOther);
end;

var
  v: Variant;
  varr: array of Variant;
  m, m2, m3: TMyRec;
  i: LongInt;
begin
  myrectype := TMyRecVarType.Create;
  try
    m.f := 42;
    m.s := 'Hello World';

    v := m;

    m2 := v;

    Writeln(m2.f, ' ', m2.s);

    varr := [1, 'Foobar', m];

    for i := Low(varr) to High(varr) do
      try
        m3 := varr[i];
        Writeln('Entry ', i, ': ', m3.f, ' ', m3.s);
      except
        Writeln('Entry ', i, ': failed to cast');
      end;
  finally
    myrectype.Free;
  end;
end.

=== code end ===

This code is merely a proof of concept and might be further improved.

Regards,
Sven
_______________________________________________
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal

Reply via email to