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.

6
  • What is "as expected"? The array is not cleared in the first case. Commented Sep 23, 2010 at 19:11
  • 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. Commented Sep 23, 2010 at 19:12
  • @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. Commented Sep 23, 2010 at 19:18
  • Sorry, if I miss something, but what is the question? "Why is this bug not resolved?" Commented Sep 23, 2010 at 19:22
  • @splash So this is a compiler bug and not just some undocumented limitation of open array parameters? Commented Sep 23, 2010 at 19:26

3 Answers 3

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

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

Comments

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.

Comments

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

3 Comments

How does P know from MyArray? Don't cheat with pointers! ;-)
While it compiles, it does not actually work. The procedure has no clue what the high-bound of the PChar is.
@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.

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.