On Mon, 10 Oct 2011 02:42:26 -0400, Norbert Nemec <[email protected]> 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@SYM32
                push    EAX
call _d_arrayliteralT@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@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

Reply via email to