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