1

I'm trying to implement array append in Delphi 7, because the standard library does not have it. This is what I have so far, but it complains about incompatible types when I try to get the length of the array.

procedure ArrayAppend(var GenericArray; const Element);
var
  len: Integer;
begin
  len := Length(GenericArray);
  SetLength(GenericArray, len+1);
  GenericArray[len] := Element;
end;

I'm trying to find what the most generic type of array is in Delphi 7.

I also have no issue returning the modified array if that's the only way to do it.

11
  • 2
    It's impossible for you to implement this in a generic way. Only the compiler is capable of doing that. How could the compiler possibly know how to perform any of these tasks without knowledge of what the element type is? You could do this if you used a modern version of Delphi. Being 13 years behind the times is hurting you. Commented Feb 10, 2015 at 15:27
  • Yeah, that's what I was afraid of. Oh yeah, I'm well aware. Now convince my company that we should move to a new language, or even just a new version of Delphi. Commented Feb 10, 2015 at 15:28
  • 1
    Use a TList - those exist even in Delphi 7. Commented Feb 10, 2015 at 15:32
  • @500-InternalServerError They are arrays of pointers rather than arrays of values Commented Feb 10, 2015 at 15:33
  • @500-InternalServerError Yeah, that's what I'm doing now. Commented Feb 10, 2015 at 15:33

1 Answer 1

2

To illustrate what Rob Kennedy said in comments, here is a function that will append a value to a dynamic array. However, this is a rather crippled function in that it does not support managed types. So you cannot have strings, interfaces, variants or dynamic arrays. Or indeed compound structures that contain any managed types.

{$APPTYPE CONSOLE}

uses
  SysUtils,
  TypInfo;

type
  PDynArrayTypeInfo = ^TDynArrayTypeInfo;
  TDynArrayTypeInfo = packed record
    kind: Byte;
    name: Byte;
    elSize: Longint;
    elType: ^PDynArrayTypeInfo;
    varType: Integer;
  end;

function DynArraySize(a: Pointer): Integer;
asm
        TEST EAX, EAX
        JZ   @@exit
        MOV  EAX, [EAX-4]
@@exit:
end;

type
  TIntegerArray = array of Integer;

procedure AppendUnmanaged(var arr{: TArray<T>}; const Value{: T}; TypeInfo: PTypeInfo);
var
  len, elSize: Integer;
begin
  len := DynArraySize(Pointer(arr)) + 1;
  DynArraySetLength(Pointer(arr), TypeInfo, 1, @len);
  inc(PAnsiChar(TypeInfo), PDynArrayTypeInfo(TypeInfo).name);
  elSize := PDynArrayTypeInfo(TypeInfo).elSize;
  Move(Value, (PAnsiChar(Pointer(arr)) + (len-1)*elSize)^, elSize);
end;

procedure Main;
var
  arr: TIntegerArray;
  i, Value: Integer;
begin
  Value := -1;
  AppendUnmanaged(arr, Value, TypeInfo(TIntegerArray));

  Value := 666;
  AppendUnmanaged(arr, Value, TypeInfo(TIntegerArray));

  Value := 42;
  AppendUnmanaged(arr, Value, TypeInfo(TIntegerArray));

  for i := low(arr) to high(arr) do
    Writeln(arr[i]);
end;

begin
  try
    Main;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.

You can see some obvious problems with this when compared with modern day Delphi which has generic types and array concatenation baked into the language. Specifically I'm thinking of these issues:

  1. You have to provide a type info to the function.
  2. You cannot pass literals because they are not valid as untyped parameters.

Now, it is certainly possible to replicate what the compiler does when assigning a managed type. But is it really worthwhile? Is the code above, especially the calling code, really an improvement over the type safe alternatives? Personally I don't think so.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.