Delphi: array of Char and TCharArray "Incompatible Types"
Asked Answered
S

4

3

I've run across this "Incompatible types" error in the comment below a few times, and never been happy with why this isn't directly supported in Delphi 2007:

program Project1; {$APPTYPE CONSOLE}

type TCharArray = array of Char;

procedure DoArray(Chars: array of Char);
begin
end;

function ReturnTCharArray: TCharArray;
var CharArray: TCharArray;
begin
  Result := CharArray;
end;

begin
  DoArray(ReturnTCharArray); // [DCC Error] Project1.dpr(18): E2010 Incompatible types: 'Array' and 'TCharArray'
end.

Shouldn't it be possible to make an array type "aliased" to another array type compatible with each other? Assuming I can't change the declaration of DoArray (it is part of a third party library), how do I write a function returning an array of char compatible with DoArray's param? The straightforward "function ReturnAChar: array of Char;" results in an "Identifier expected but 'ARRAY' found" error. I even tried changing the function returning the array to a procedure with a var "array of Char" pram, but that also doesn't allow setting the length of the "array of Char" param in the procedure ("Constant object cannot be passed as var parameter").

Sixteenth answered 23/9, 2010 at 16:0 Comment(0)
S
5

This may actually be a compiler bug (or a limitation that was never documented properly). I did some experimentation and found that you can pass a dynamic array (typed or not) to a procedure expecting an open array for almost every type... except Char and WideChar.

See Is a dynamic array of Char allowed when the parameter type is open array of Char? for a description of the problem and a possible work around.

Staton answered 23/9, 2010 at 19:42 Comment(3)
For some reason, I always thought that dynamic arrays and open arrays were incompatible... I'm actually pretty surprised only char and Widechar are. Looks like they were those involved in my early experimentation with Delphi arrays, and I never went back to it. Or maybe it was in Delphi 5?Succory
@Ken The documentation claims open array parameters can handle any array of the same type. So I was just as surprised that array of Char and array of WideChar didn't compile.Staton
@KennethCochran: It should accept any array, even array of Char/WideChar.Gilbart
A
4

When typed @ operator is off the compiler does not check what you assign to a pointer, so you can call a procedure with wrong parameters:

program Project1; {$APPTYPE CONSOLE}

type TCharArray = array of Char;

procedure DoArray(Chars: array of Char);
begin
end;

function ReturnTCharArray: TCharArray;
var CharArray: TCharArray;
begin
  Result := CharArray;
end;

type TFakeDoArray = procedure(Chars: TCharArray);

var
  FakeDoArray: TFakeDoArray;
begin
  FakeDoArray := @DoArray;
  FakeDoArray(ReturnTCharArray);
end.

While the compiler won't complain, for the very reason 'Jeroen' indicates in his comment for Mason's answer, this will not work.

You can then try declaring your fake procedure compatible with one with an open array parameter:

program Project1; {$APPTYPE CONSOLE}

type TCharArray = array of Char;

procedure DoArray(Chars: array of Char);
begin
end;

function ReturnTCharArray: TCharArray;
var CharArray: TCharArray;
begin
  Result := CharArray;
end;

type
  TFakeDoArray = procedure(AnArray: Pointer; High: Integer);

var
  FakeDoArray: TFakeDoArray;
  Tmp: TCharArray;
begin
  FakeDoArray := @DoArray;
  Tmp := ReturnTCharArray;
  FakeDoArray(Tmp, High(Tmp));
end.

Credits are due Rudy for his great article. And the relevant documentation (from Program Control):

An open-array parameter is passed as two 32-bit values. The first value is a pointer to the array data, and the second value is one less than the number of elements in the array.

Amitie answered 23/9, 2010 at 18:32 Comment(0)
A
2

You don't. Pascal handles array types by name, not by description, and always has. Why can't you change the declaration of DoArray? (And why was it written like that in the first place?)

Ascribe answered 23/9, 2010 at 16:4 Comment(9)
+1; right! (Oh BTW: there is also the "open array" versus "typed array" thing, that's probably where the Anagoge is going to bump into next)Funest
DoArray is part of a third party library that I don't want to (and realistically can't) edit. I can understand you sometimes want the type safety of types by name, but this language restriction is more annoying than helpful, to me. Is there not a way to convince Delphi to return a literal/exact "array of Char" from a function? That seems like a fairly basic request.Sixteenth
@Anagoge: No, there isn't as far as I know. I think that's why they added TArray<T> in Delphi 2009. TArray<T> is defined as array of T, but since it's now a named type, it gets around all these issues.Ascribe
For some reason, I always thought that dynamic arrays and open arrays were incompatible...Succory
This answer misses the point by some distance. DoArray accepts an open array.Amish
I can't check with D2007, but DoArray should accept any array, both static and dynamic arrays of Char. If it doesn't, this is definitely a bug. The compiler knows the type of array and inserts code to pass the proper data (pointer and High value) to the function/procedure.Gilbart
@KenBourassa: dynamic arrays are types, open arrays are a way to pass arrays as parameters. But open arrays do accept dynamic arrays as parameters. So you can pass a dynarray as open array, but you can't assign an open array to a dynarray, or use procedures like SetLength on an open array parameter.Gilbart
@Rudy This is a compiler bug. This should not be the most upvoted answer. The community spirited thing to do here is to downvote this.Amish
@David: I fully agree. Done.Gilbart
S
-1

One point that I didn't see mentioned yet is that TCharArray is a dynamic array type, while in

procedure DoArray(Chars: array of Char); 

Chars is an open array parameter. There is no syntax to declare a dynamic array parameter. To have a dynamic array parameter, it needs to be declared as a type.

type
  TMyDynArray = array of Integer;

procedure DoArray(Integers : TMyDynArray);
Succory answered 23/9, 2010 at 19:32 Comment(2)
This is incorrect. Any form of array can be passed to an open array parameter. That the compiler rejects this is because the compiler is defective.Amish
And where do I, in this answer, mention that dynamic arrays can't be passed as open array parameter? I only mention that array of char as a parameter doesn't make the parameter a dynamic array but an open array one. And since the question complains he can't use "SetLength" in the DoArray function, it suggests that what he wants isn't an open array parameter. And what with the necro?Succory

© 2022 - 2024 — McMap. All rights reserved.