Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2021-06

Tuples as variant arrays

3 messages · 3 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Ryan Joseph

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.

Regards,
Ryan Joseph

Michael Van Canneyt
Dennis Lee Bieber wrote 37 lines
On Fri, 25 Jun 2021 16:12:41 -0600, Ryan Joseph via fpc-pascal declaimed the following: > 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; > Uhm, is there supposed to be some name designating storage space inside that record declaration? Just my initial observation -- my Pascal experience is Jensen&Wirth via UCSD (college, on LSI-11) and Alcor (on TRS-80 Model 4). > var > t: TTuple; > r: MyRecord; > i: variant; > begin > t := [1,'string', r]; https://wiki.freepascal.org/Variant """ Values of any simple data type can be stored in a variant variable. """ ... would seem to reject the use of a record type (as records are, themselves, made up of other "simple data types").

It is not possible to do this unless you create some custom variant manager that can handle this. But even so, you'd need to make it a pointer to a record, as a variant has limited, fixed size.

Michael.

Sven Barth
to Ryan Joseph: Is it possible something like this could work? Seems like it should but I get an error…
Ryan Joseph wrote 26 lines
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