I was looking at Delphi: array of Char and TCharArray "Incompatible Types" and started experimenting. What I discovered is rather interesting.
procedure Clear(AArray: array of Integer);
var
I: Integer;
begin
for I := Low(AArray) to High(AArray) do
AArray[I] := 0;
end;
var
MyArray: array of Integer;
begin
Clear(MyArray);
end.
This simple little example shows how you can pass a Dynamic Array to a procedure using an Open Array parameter. It compiles and runs exactly as expected.
procedure Clear(AArray: array of Char);
var
I: Integer;
begin
for I := Low(AArray) to High(AArray) do
AArray[I] := #0;
end;
var
MyArray: array of Char;
begin
Clear(MyArray);
end.
Here is nearly identical code the only difference being it is using an array of Char
rather than Integer
. It does not compile. Instead the compiler spits out:
E2010 Incompatible types: 'Array' and 'Dynamic array'
Why would this be?
After searching for a while I discovered this QC report. I'm running Delphi 2009 and its still happening.
Since the documentation specifically mentions open array parameters of type Char to be compatible with dynamic arrays, this should be a bug. From 'Open Array Parameters':
function Find(A: array of Char):
Integer;
[...]
Note: [...] The previous example creates a function that takes any array of Char elements, including (but not limited to) dynamic arrays. [...]
You can work with this kind of array, defining your own type:
type
TCharDynArray = array of char;
procedure Clear(AArray: TCharDynArray);
var
I: Integer;
begin
for I := Low(AArray) to High(AArray) do
AArray[I] := #0;
end;
procedure test;
var
MyArray: TCharDynArray;
begin
Clear(MyArray);
end;
This code will compile fine. It doesn't do anything useful of course (the AArray parameter is not set as "var", so it's copied on the stack before assigning a #0 to every item). But at least, it compiles.
In practice, I found out more easy to define or use high-level of types for dynamic arrays (like TIntegerDynArray), because at least it allows you to pass the array as reference, using a var, therefore avoiding to make a copy on stack, and make your code faster.
About the mapping to a PChar, it's usual for all dynamic arrays: you can map a TIntegerDynArray to a pointer, then use it as a PInteger or a PIntegerArray:
procedure AddInteger(var Values: TIntegerDynArray; Value: integer);
var n: integer;
begin
n := Length(Values);
SetLength(Values,n+1);
Values[n] := Value;
end;
procedure Loop(V: PInteger);
begin
if V<>nil then
while V^<>0 do begin
write(V^,' ');
inc(V); // go to next integer in array
end;
end;
var IntArray: TIntegerDynArray;
begin
Loop(pointer(IntArray)); // will display nothing, since pointer(IntArray)=nil for IntArray=[]
AddInteger(IntArray,2);
AddInteger(IntArray,3);
AddInteger(IntArray,0);
Loop(pointer(IntArray)); // will display '2 3 '
end.
The problem is the "array of char" code beeing inconsistent with "array of integer" is certainly in compiler intrinsics, and the fact that a PChar can be type-casted to a string.
I think the reason is that array of Char
is compatible with PChar
, as this code does compile:
procedure Clear(AArray: array of Char);
var
I: Integer;
begin
for I := Low(AArray) to High(AArray) do
AArray[I] := #0;
end;
var
MyArray: array of Char;
P: PChar;
begin
Clear(P^);
end.
That is probably for historic reasons.
Hopefully Barry Kelly or Danny Thorpe will kick in and provide some more feedback on this.
--jeroen
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With