views:

247

answers:

3

Using D2010, I'd like to do something like this:

procedure SizeArray(var aArr: array of integer; aSize: integer);
begin
  SetLength(aArr,aSize);
end;

But this fails to compile. Because my "aArr" parameter isn't a dynamic array, it's an open array parameter. And SetLength cannot be called on it. The only way I know of to force the parameter to be a dynamic array is to give it a type name, like so:

type
  TIntArray = array of integer;

procedure SizeArray(var aArr: TIntArray; aSize: integer);
begin
  SetLength(aArr,aSize);
end;

And now the code compiles. And it works fine, for the most part, but this fails:

procedure Test;
var
  a : array of integer;
begin
  SizeArray(a,5);
end;

Because types of actual and formal var parameters must be identical and the compiler doesn't recognize "array of integer" and "TIntArray" as identical types.

So, here's my question: Is there some way I can get the compiler to identify my var parameter as a dynamic array rather than as an open array so that the caller can declare a simple "array of integer" rather than some named type?

Thanks in advance.

A: 

No, there's no way to do that. It's part of the Pascal language specification and isn't likely to change.

EDIT: Skamradt found a way. Let me restate that. There's no way to do that safely.

Mason Wheeler
Ah, but programming without rails adds a bit of adrenaline to the mix. ... oh, wait, that was the jolt cola from the last round of all night debugging. :)
skamradt
I program without rails all the time. Never been a big fan of Ruby, to be honest... ;)
Mason Wheeler
+9  A: 

This is indeed possible...just use the absolute keyword along with an untyped var.

procedure SizeArray(var aArr; aSize: integer);
var
  ActArr : Array of Integer absolute aArr;
begin
  SetLength(ActArr,aSize);
end;

var
  Test : Array of Integer;
begin
  SizeArray(Test,5);
  showMessage(IntTostr(High(Test)));  // -- returns 4
end;
skamradt
+1 for extreme cleverness. I've already started down Barry Kelly's path, so I'm accepting his answer. But, for finding a way... I'm impressed. :)
TrespassersW
+9  A: 

Pascal, and by extension Delphi, uses name equivalence rather than structural equivalence for array types, including dynamic arrays. Variables declared with a type that doesn't have a name, like this:

var
  x: array of Integer;

... end up using an anonymous name that isn't equivalent to any other type's name. That's why you get the error. The error can be useful; for example, consider an array of Kilometers vs an array of Kilograms - but it's often the case that declaring a name for every distinct type is inconvenient.

To get around this issue, and staying within the safe type system (so avoiding untyped parameters, as skamradt suggests), I recommend using the same name for every particular array shape. You can do this to a reasonably large degree by using the TArray<T> type declared in the System unit. So, instead of working with array of Integer, use TArray<Integer>.

TArray<T> is declared like this:

type
  TArray<T> = array of T;

... so it can supply a name for arbitrary dynamic arrays.

Barry Kelly
I hadn't noticed the declaration in System. That's nice. I think getting into the habit of declaring my arrays this way will be useful. At first I thought the TArray in System conflicted with the one in Generics.Collections, but I guess it doesn't since that one isn't a generic. This is a nice solution. Thanks.
TrespassersW