Search code examples
arraysdelphidelphi-7

Array of data types


For reasons I need to have something like this:

DT: array[0..3] of types = (string, integer, double, boolean);

Is this even possible?


Solution

  • Even if it would compile, the resulting DT[] array won't be usable for any profit.

    You could only use something like

    var v: DT[0]; // this will be a string variable
    

    but it is clearly pointless, since you have in particular the ability to define custom types:

    type
      TMyString = type string; 
    ...
     var
       v: TMyString;
    

    So replace TMyString by DT[0] and you get what you expect.

    If you expect to use DT[] e.g. with a loop, e.g. use DT[i], I don't see any possible use of this syntax.

    What I usually do on the other hand, is either:

    • use variant variable to store any kind of value - I guess this is what you wanted to reinvent;
    • use an enumerate meta-classes to initiate a given class on the fly.

    First, variant values are pretty powerful:

    var v: variant;
    begin
      v := 1; // now v holds an integer
      ShowMessage(v); // will be converted to string before display
      if VarIsStr(v) then // false
        ShowMessage('string')
      else if VarIsNumeric(v) then // true
        ShowMessage('number');
      v := 'toto'; // now v holds a string
      ShowMessage(v);
      if VarIsStr(v) then // true
        ShowMessage('string')
      else if VarIsNumeric(v) then // false
        ShowMessage('number');
      v := true;   // now v holds a boolean
      if VarIsStr(v) then // false
        ShowMessage('string')
      else if VarIsNumeric(v) then // false
        ShowMessage('number')
      else if VarIsBool(v) then // true
        ShowMessage('boolean');  
    ...
    

    And for metaclasses:

    type
      TMyClassParent = class
      ...
      end;
    
      TMyClass1 = class(TMyClassParent)
      ...
      end;
      TMyClass2 = class(TMyClassParent)
      ...
      end;
      TMyClass3 = class(TMyClass1)
      ...
      end;
    
      // define the meta-class type
      TMyClassParentClass = class of TMyClassParent;
      // define an enumeration
      TMyClasses = (myclass1, myclass2, myclass3);
    
    const
      MYCLASS_NAME: array[TMyClasses] of string = (
         'one', 'two', 'three');
      MYCLASS_CLASS: array[TMyClasses] of TMyClassParentClass = (
        TMyClass1, TMyClass2, TMyClass3);
    
    var
      c: TMyClassParent;
      cc: TMyClasses;
    begin
      for cc := low(cc) to high(cc) do
      begin
        writeln('Using ', MYCLASS_CLASS[cc].ClassName, ' for class ', MYCLASS_NAME[cc]);
        c := MYCLASS_CLASS[cc].Create;
        try
          // use Liskov's friendly c instance
        finally
          c.Free;  
        end;
      end;
    end.
    

    And if you follow properly Liskov's substitution principle, you may use c: TMyClassParent in an abstract manner, since the children wouldn't affect the expectations of the parent class behavior.