Is a dynamic array of Char allowed when the parameter type is open array of Char?
Asked Answered
C

3

11

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.

Cranky answered 23/9, 2010 at 19:5 Comment(6)
What is "as expected"? The array is not cleared in the first case.Scuttle
Still, +1, for only one of the cases do compile (even if we use AnsiChar), which is rather odd, for there is very little difference between an integer and an AnsiChar.Scuttle
@Andreas, Ok you got me there. An empty array has nothing to clear. My test code had a call to SetLength but I removed it as it wasn't directly relevant to the compilation error.Cranky
Sorry, if I miss something, but what is the question? "Why is this bug not resolved?"Amanita
@Amanita So this is a compiler bug and not just some undocumented limitation of open array parameters?Cranky
I see! I missed the [closed] tag in the CQ report (maybe it's to late for me), but if I should guess, I would say it's still the same bug. ;-)Amanita
S
4

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. [...]

Spherics answered 24/9, 2010 at 1:10 Comment(0)
L
4

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.

Lobate answered 6/1, 2011 at 8:55 Comment(0)
K
2

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

Klement answered 23/9, 2010 at 19:38 Comment(3)
How does P know from MyArray? Don't cheat with pointers! ;-)Amanita
While it compiles, it does not actually work. The procedure has no clue what the high-bound of the PChar is.Spherics
@Sertac: I totally agree it is a bug somewhere; just wanted to point out where it it might come from. Hopefully Barry or Danny will shed some light here.Klement

© 2022 - 2024 — McMap. All rights reserved.