Recent

Author Topic: Various Variant Arrays  (Read 370 times)

egsuh

  • Hero Member
  • *****
  • Posts: 1794
Various Variant Arrays
« on: May 06, 2026, 02:02:04 pm »

I'm playing with several methods using variant arrays. Intuitively the fourth method seems clearest, but it needs case statement. Which method would you prefer? Are there any other methods? Currently I'm using method 3, but simply I'm simply looking for ways not requiring explicit type conversion. Unix guideline recommends strings.


Code: Pascal  [Select][+][-]
  1.  
  2. implementation
  3.      procedure ShowValues1(args: array of variant);
  4.      procedure ShowValues2(args: variant);
  5.      procedure ShowValues3(args: array of string);
  6.      procedure ShowValues4(args: array of const);
  7.  
  8. implementation
  9.  
  10. function TForm1.addone(i: integer): string;
  11. begin
  12.   Result := IntToStr(i + 1);
  13. end;
  14.  
  15. //----------------- using varray of variant ------------
  16. procedure TForm1.Button1Click(Sender: TObject);
  17. begin
  18.    showvalues1([1,'996', 88, '587']);
  19. end;
  20.  
  21. procedure TForm1.ShowValues1(args: array of variant);
  22. var
  23.    ti: integer;
  24. begin
  25.    for ti := Low(args) to High(args) do
  26.        memo1.lines.add(addone(args[ti]));
  27. end;
  28.  
  29. //------------------ using VarArrayOf ---------------------
  30. procedure TForm1.Button2Click(Sender: TObject);
  31. begin
  32.    showvalues2(VarArrayOF([1,'996', 88, '587']));
  33. end;
  34.  
  35. procedure TForm1.ShowValues2(args: variant);
  36. var
  37.    ti: integer;
  38. begin
  39.    for ti := VarArrayLowBound(args, 1) to VarArrayHighBound(args, 1) do
  40.        memo1.lines.add(addone(args[ti]));
  41. end;
  42.  
  43.  
  44. //------------------------------ using array of string ----------------------
  45. procedure TForm1.Button3Click(Sender: TObject);
  46. begin
  47.    showvalues3([IntToStr(1),'996', IntToStr(88), '587']);
  48. end;
  49.  
  50. procedure TForm1.ShowValues3(args: array of string);
  51. var
  52.    ti: integer;
  53. begin
  54.    for ti := Low(args) to High(args) do
  55.        memo1.lines.add(addone(StrToInt(args[ti])));
  56. end;
  57.  
  58.  
  59. //---------------------------  using array of const --------------------------
  60. procedure TForm1.Button4Click(Sender: TObject);
  61. begin
  62.    showvalues4([1,'996', 88, '587']);
  63. end;
  64.  
  65. procedure TForm1.ShowValues4(args: array of const);
  66. var
  67.    ti: integer;
  68.    tj: integer;
  69. begin
  70.    for ti := Low(args) to High(args) do begin
  71.        case args[ti].VType of
  72.           vtInteger: tj := args[ti].vInteger;
  73.           vtAnsistring: tj := StrToInt(AnsiString(args[ti].vAnsiString));
  74.        end;
  75.        memo1.lines.add(addone(tj));
  76.    end;
  77. end;
  78.  

LemonParty

  • Sr. Member
  • ****
  • Posts: 468
Re: Various Variant Arrays
« Reply #1 on: May 06, 2026, 02:57:46 pm »
I prefer array of string too. Variants is an additional dependency, if other libraries not need variants I will abstain of using it. Beside using variants is not performance free.
Lazarus v. 4.99. FPC v. 3.3.1. Windows 11

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12345
  • Debugger - SynEdit - and more
    • wiki
Re: Various Variant Arrays
« Reply #2 on: May 06, 2026, 03:25:04 pm »
Array of const is IMHO good. But there is another way:

Code: Pascal  [Select][+][-]
  1. program Project1;
  2. {$Mode objfpc}
  3.  
  4. uses SysUtils;
  5.  
  6. type
  7.   TMyVal = record s: string; end; // unique type, only used for ShowValues
  8.  
  9. operator := (v: string): TMyVal; begin Result.s := v; end;
  10. operator := (v: char): TMyVal; begin Result.s := v; end;
  11. operator := (v: integer): TMyVal; begin Result.s := IntToStr(v); end;
  12. operator := (v: boolean): TMyVal; begin Result.s := BoolToStr(v); end;
  13.  
  14. procedure ShowValues({const} args: array of TMyVal);
  15. var
  16.   t: TMyVal;
  17. begin
  18.   for t in args do write(t.s);
  19.   writeln;
  20. end;
  21.  
  22. begin
  23.   ShowValues(['a', 'abc', 1, True]);
  24.   readln;
  25. end.
  26.  


You do want the array have "const args: ..."

Otherwise (in any of the array cases) the code will make a copy of the entire array


And you can also add "inline;" to the operators.
« Last Edit: May 06, 2026, 03:31:05 pm by Martin_fr »

Khrys

  • Sr. Member
  • ****
  • Posts: 438
Re: Various Variant Arrays
« Reply #3 on: May 06, 2026, 04:30:21 pm »
const array of const  is king - no copying, no reference counting.
Personally I'd use that + assignment operator overloads on  TVarRec.

egsuh

  • Hero Member
  • *****
  • Posts: 1794
Re: Various Variant Arrays
« Reply #4 on: May 08, 2026, 09:35:12 am »
I got some idea. My final solution is similar to the following.

Code: Pascal  [Select][+][-]
  1. // Calling unit
  2. unit GlobalUnit;
  3.  
  4. interface
  5.  
  6. type
  7.     Icommon = interface
  8.            function GetFunction (funcID: integer;  args: array of variant): string;
  9.     end;
  10.  
  11. operator := (v: TVarRec): Variant;
  12.  
  13. function Func1 (pid:string) : string;
  14. function Func2 (pid:string; sid: integer): integer;
  15. function Func3 (pid:string; sid:integer; strparam: string; intparam: integer): boolean;
  16. // ... and so on
  17.  
  18. var
  19.     intf: Icommon;
  20.  
  21. implementation
  22.  
  23.     operator := (v: TVarRec): Variant;
  24.     begin
  25.        case v.VType of
  26.            vtInteger    :  Result := v.VInteger;
  27.            vtString     :  Result := string(v.VString^);
  28.            vtBoolean    :  Result := v.VBoolean;
  29.            vtAnsiString :  Result := AnsiString(v.VAnsiString);
  30.            else;
  31.        end;
  32.     end;
  33.  
  34.      function Func1 (pid:string) : string;
  35.      begin
  36.           Result := intf.GetFunction (1, [pid]);
  37.      end;
  38.  
  39.      function Func2 (pid:string; sid: integer): integer;
  40.      begin
  41.           Result := StrToInt(intf.GetFunction (2, [pid, sid]));
  42.      end;
  43.  
  44.      function Func3 (pid:string; sid:integer; param1: string; param2: integer): boolean;
  45.      begin
  46.           Result := StrToBool(intf.GetFunction (2, [pid, sid, strparam, intparam]));
  47.      end;
  48.     ...
  49. end;
  50.  
  51. /////////////////////////
  52.  
  53. and at the unit implementing interface,
  54.  
  55. interface
  56.  
  57. type
  58.      TDM = class(TDataModule, Icommon)
  59.            function GetFunction (funcID: integer;  args: array of variant): string;
  60.  
  61.            function Func1 (pid:string) : string;
  62.            function Func2 (pid:string; sid: integer): integer;
  63.            function Func3 (pid:string; sid:integer; strparam: string; intparam: integer): boolean;
  64.      end;
  65.  
  66. implementation
  67.      
  68.      function TDM.GetFunction (funcID: integer;  args: array of variant): string;
  69.      begin
  70.           case funcID of
  71.               1: Result := Func1(args[0]);
  72.               2: Result := IntToStr (Func2(args[0], args[1]));
  73.               3: Result := BoolToStr(Func3(args[0], args[1], args[2], args[3]));
  74.          end;
  75.     end;
  76.  
  77.  
  78.      function TDM.Func1 (pid:string) : string;
  79.      begin
  80.           // ...........  do some operations ..........
  81.           Result := 'some string';
  82.      end;
  83.  
  84.      function TDM.Func2 (pid:string; sid: integer): integer;
  85.      begin
  86.           // do something;
  87.           Result := someinteger;
  88.      end;
  89.  
  90.      function TDM.Func3 (pid:string; sid:integer; param1: string; param2: integer): boolean;
  91.      begin
  92.           // do something;
  93.           Result := true;
  94.      end;
  95.  
  96. end;
  97.  

I haven't tested this in full. Simply changed a few functions, and it compiles without problem (haven't run with real data).

I know that it is possible to put every function of func1, func2, and func3 interfaced (through Icommon). But this made the whole program more complex, as there are two different data modules that implement the interface (Icommon). So came to think of this approach, in which I do not have to mind var type of parameters.

I'd like to get comments or recommendations, and expected problems if any.


egsuh

  • Hero Member
  • *****
  • Posts: 1794
Re: Various Variant Arrays
« Reply #5 on: May 08, 2026, 10:37:31 am »
If the TVarRec is processed automatically as parameter of functions like Variant, then it would be helpful.

Thaddy

  • Hero Member
  • *****
  • Posts: 19156
  • Glad to be alive.
Re: Various Variant Arrays
« Reply #6 on: May 08, 2026, 10:56:20 am »
I think the parameters should be Variant, not TVarRec, although that might work.
And in that case the operator is not necessary:
Code: Pascal  [Select][+][-]
  1. program vartests;
  2. {$mode objfpc}{$H+}
  3. uses variants;
  4. var
  5.   x,y,z:variant;
  6.   a:integer;
  7.   b:string;
  8.   c:Boolean;
  9. begin
  10.   x := 100;
  11.   y := 'Test';
  12.   z := false;
  13.   a := x;
  14.   b := y;
  15.   c := z;
  16.   writeln(a,b,c);
  17. end.
The compiler will mark an overload with variant parameter as "impossible", because it is already implemented by the compiler.

Note that handling variants is easy and convenient, but also dead slow, TvarRec or variant.
« Last Edit: May 08, 2026, 11:06:33 am by Thaddy »
objects are fine constructs. You can even initialize them with constructors.

egsuh

  • Hero Member
  • *****
  • Posts: 1794
Re: Various Variant Arrays
« Reply #7 on: May 08, 2026, 11:33:28 am »
No... operator overload is not necessary.

Thaddy

  • Hero Member
  • *****
  • Posts: 19156
  • Glad to be alive.
Re: Various Variant Arrays
« Reply #8 on: May 08, 2026, 11:45:14 am »
Hope it helped. You were on the right track.
objects are fine constructs. You can even initialize them with constructors.

egsuh

  • Hero Member
  • *****
  • Posts: 1794
Re: Various Variant Arrays
« Reply #9 on: May 08, 2026, 11:54:02 am »
Quote
Hope it helped. You were on the right track.
Note that handling variants is easy and convenient, but also dead slow, TvarRec or variant.

Thank you for your advice. Speed doesn't matter in my case. All the functions are to send command from user interface to internal operations.

egsuh

  • Hero Member
  • *****
  • Posts: 1794
Re: Various Variant Arrays
« Reply #10 on: May 08, 2026, 06:16:24 pm »
Sorry. I was confused a bit.
If "array of const" + operator overload is recommended instead of "array of variant", it should be in following way.

Code: Pascal  [Select][+][-]
  1. function GetFunction (funcID: integer; const args: array of const): string;
  2.  
  3. operator := (v:TVarRec): integer; begin Result := v.vInteger; end;
  4. operator := (v:TVarRec): string; begin Result := AnsiString(v.vAnsiString); end;
  5. operator := (v:TVarRec): boolean; begin Result := v.vBoolean; end;
  6.  

Only these three types are used for now.
Does the operator overload work only within the unit?

 

TinyPortal © 2005-2018