Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I define an array type of different types?

I'd like to define an array type which consists of different types, such as String, Integer, Boolean, Double, etc. but no objects, structures, or anything of that nature. Then I'd like to use this type as a function argument, for example...

type
  TMyArray = array of ...?...;

function GetSomething(const Input: TMyArray): String;
var
  X: Integer;
begin
  for X:= 0 to Length(Input) - 1 do begin
    //Identify type and handle accordingly...
    //Serialize data for the result...

  end;
end;

and use it like...

Variable:= GetSomething(['some string', 123, 'something else', 12.3, false]);

Then, how do I identify what type each element is when iterating through such an array?

I'm pretty sure this is possible, but have no idea even what terminology to search for. How do I do this?

Would I have to define this as an array of Variants? Or is there a way to define exactly which types the array accepts?

EDIT

Not to change the question any, but after the answer by RRUZ, I found an intriguing article about the performance when doing this exact thing different ways...

like image 864
Jerry Dodge Avatar asked Sep 18 '13 01:09

Jerry Dodge


People also ask

Can you have multiple types in an array?

Arrays that contain instances of multiple types are often referred to as heterogenous arrays, and are incredibly commonly used in dynamically typed languages — like PHP, JavaScript, and Ruby.

How do you create an array of different types?

To create an array type you can use Array<Type> type where Type is the type of elements in the array. For example, to create a type for an array of numbers you use Array<number> . You can put any type within Array<Type> .

Can array be of any type?

The values in an array can be any type, so that arrays may contain values that are simple reals or integers, vectors, matrices, or other arrays.

Can you have an array of different types in Java?

In java, is it possible to create an array or any sort of collection which can hold different data types? Yes.


3 Answers

If your Delphi version supports RTTI, you can use an array of TValue and the Kind property like so.

{$APPTYPE CONSOLE}


uses
  System.TypInfo,
  System.Rtti,
  System.SysUtils;


function GetSomething(const Input: array of TValue): String;
var
  X: Integer;
  LValue : TValue;
begin
  for LValue in Input  do begin
     case LValue.Kind of
       tkUnknown: Writeln('Unknown');
       tkInteger:  Writeln(Format('The Kind of the element is Integer and the value is %d',[LValue.AsInteger]));
       tkChar: Writeln('Char');
       tkEnumeration: if LValue.TypeInfo=TypeInfo(Boolean) then Writeln(Format('The Kind of the element is Boolean and the value is %s',[BoolToStr(LValue.AsBoolean, True)]));
       tkFloat: Writeln(Format('The Kind of the element is Float and the value is %n',[LValue.AsExtended]));
       tkString: Writeln('String');
       tkSet: Writeln('Set');
       tkClass: Writeln('Class');
       tkMethod:Writeln('method');
       tkWChar: Writeln('WChar');
       tkLString: Writeln('String');
       tkWString: Writeln('String');
       tkVariant: Writeln('Variant');
       tkArray: Writeln('Array');
       tkRecord: Writeln('Record');
       tkInterface: Writeln('Interface');
       tkInt64: Writeln('Int64');
       tkDynArray: Writeln('DynArray');
       tkUString:  Writeln(Format('The Kind of the element is String and the value is %s',[LValue.AsString]));
       tkClassRef:  Writeln('Class Ref');
       tkPointer: Writeln('Pointer');
       tkProcedure:  Writeln('procedure');
     end;
  end;
end;

begin
  try
    GetSomething(['some string', 123, 'something else', 12.3, false]);
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.

Another option is use an array of const

{$APPTYPE CONSOLE}

uses
  SysUtils;


procedure GetSomething(const Input: array of const);
var
  LIndex: Integer;
begin
  for LIndex := Low(Input) to High(Input) do
  begin
    case Input[LIndex].VType of
      vtWideString: Writeln('WideString = ''', WideString(Input[LIndex].VWideChar), '''');
      vtInt64: Writeln('Int64 = ', Input[LIndex].VInt64^);
      vtCurrency: Writeln('Currency = ', CurrToStr(Input[LIndex].VCurrency^));
      vtInteger: Writeln('Integer = ', Input[LIndex].VInteger);
      vtBoolean: Writeln('Boolean = ', BoolToStr(Input[LIndex].VBoolean, True));
      vtChar: Writeln('Char = ''', Input[LIndex].VChar, '''');
      vtExtended: Writeln('Extended = ', FloatToStr(Input[LIndex].VExtended^));
      vtString: Writeln('ShortString = ''', Input[LIndex].VString^, '''');
      vtPChar: Writeln('PChar = ''', Input[LIndex].VPChar, '''');
      vtAnsiString: Writeln('AnsiString = ''', Ansistring(Input[LIndex].VAnsiString), '''');
      vtWideChar: Writeln('WideChar = ''', Input[LIndex].VWideChar, '''');
      vtPWideChar: Writeln('PWideChar = ''', Input[LIndex].VPWideChar, '''');
      vtUnicodeString : Writeln('UnicodeString = ''', string(Input[LIndex].VUnicodeString), '''');
    else
      Writeln('Unsupported');
    end;
  end;
end;

begin
  try
    GetSomething(['some string', 123, 'something else', 12.3, false]);
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.
like image 188
RRUZ Avatar answered Sep 28 '22 19:09

RRUZ


Arrays are homogeneous. As the documentation says:

An array represents an indexed collection of elements of the same type (called the base type).

Therefore you can achieve your goal only by way of a base type that can hold differing types of data. Such a data type is known as a variant data type.

In Delphi there are a number of possibilities for variant data types. There is the venerable COM Variant type. There is the new kid on the block, TValue, which was added to support new style RTTI. And there are many third party options. Typically these third party options exist to support persistence frameworks.

like image 37
David Heffernan Avatar answered Sep 28 '22 20:09

David Heffernan


Oddly enough, nobody has yet mentioned variant records, which have been a feature of Pascal for decades:

type
  TVarRecType = (vrtInteger, vrtDouble {other types go here});
  TVarRec = record
    Field1: string; { can be omitted }
  case RecType: TVarRecType of
    vrtInteger:
      IntValue: integer;
    vrtDouble:
      DblValue: double;
    { other cases go here }
  end;

var
  VarRec: TVarRecType;
begin
  VarRec.Field1 := 'This is an example.';
  VarRec.RecType := vrtInteger;
  VarRec.IntValue := 4711;
  {...}
  VarRec.RecType := wrtDouble;
  VarRec.DblValue := Pi;
  {...}
end;

{ Oops, forgot the array part }
type
  TVarRecArr = array[1..15] of TVarRec;
var
  VarRecArr: TVarRecArr;
begin
  VarRecArr[1].Field1 := 'This is the first record';
  VarRecArr[1].RecType := wrtInteger;
  VarRecArr[1].IntValue := 1;
  {...}
end;
like image 25
dummzeuch Avatar answered Sep 28 '22 18:09

dummzeuch