Static arrays, typeof and IFTI?
Steven Schveighoffer
schveiguy at yahoo.com
Tue Oct 11 08:04:01 PDT 2011
On Mon, 10 Oct 2011 02:42:26 -0400, Norbert Nemec
<Norbert at nemec-online.de> wrote:
> Hi there,
>
> after a very busy and eventful year in my personal life, I have now
> finally found some time to play with D2. I am very impressed by the
> progress!
>
> One thing I noticed was that static arrays are somehow strangely limited:
>
> It is possible to overload based on the length:
>
> --------
> void f(int[3] x) {
> writeln("int[3]: ",x);
> }
>
> void f(int[4] x) {
> writeln("int[4]: ",x);
> }
>
> int main(string argv[]) {
> f([1,2,3]);
> f([1,2,3,4]);
> return 0;
> }
> --------
>
> However, used as function template argument, a static array is casted to
> a dynamic array:
>
> -----------
> void g(T)(T x) {
> static assert (__traits(isStaticArray,T));
> enum N = T.init.length;
> writeln(N,": ",x);
> }
>
> int main(string argv[]) {
> g([1,2,3]);
> return 0;
> }
> ------------
>
> gives the error message:
>
> | Error: static assert (__traits(isStaticArray,int[])) is false
> | instantiated from here: g!(int[])
>
> Without the assertion, N is defined to 0.
>
> Further investigation shows:
>
> -------
> g!(int[3])([1,2,3]); // passes a static array
> -------
> int[3] x3 = [1,2,3];
> g(x3); // passes a static array
> -------
> auto z3 = [1,2,3]; // defines z3 as dynamic array
> g(y3); // passes a dynamic array
> -------
>
> So it seems, the problem is that array literals on their own turned into
> dynamic arrays unless you explicitly state a static array type in some
> way.
In fact, all array literals are dynamic. Examine the code for
g!(int[3])([1,2,3]) (comments added):
push 3
push 2
push 1
push 3
mov EAX,offset FLAT:_D12TypeInfo_G3i6__initZ at SYM32
push EAX
call _d_arrayliteralT at PC32 ; create dynamic array
literal
add ESP,014h
mov EBX,EAX
push dword ptr 8[EBX] ; copy the data from the
heap-allocated literal into the fixed-sized array temporary
push dword ptr 4[EBX]
push dword ptr [EBX]
call _D10testdynarr10__T1gTG3iZ1gFG3iZv at PC32 ; call g
So really, the situation is worse than you thought :)
>
> Wouldn't it make more sense the other way around? After all, turning a
> static array into a dynamic array is easy, the other way around is
> prohibited by the compiler. If array literals simply had a static array
> type, they could be implicitly casted to dynamic arrays when necessary
> but stay static if possible.
D1 I think works that way (array and string literals are fixed-sized array
arrays). Most of the time, you don't want a static array to be passed.
Remember that fixed-size arrays are passed by *value* not by reference.
This means any large array will be fully pushed onto the stack to pass it,
not just a slice.
It also adds (most of the time unnecessarily) bloat. Think of string
literals:
foo(T)(T x)
{
writeln(x);
}
foo("hello");
foo("goodbye");
In D1, this creates *two* different instantiations of foo, one for
char[5u] and one for char[7u]. In D2 if fixed-sized array were the
default choice, both "hello" and "goodbye" would be passed by value,
meaning pushing all the data on the stack, in addition to creating the
bloat.
I do agree writing a fixed-size array literal should be easier than it is.
-Steve
More information about the Digitalmars-d
mailing list