Troubles with immutable arrays

kenji hara k.hara.pg at gmail.com
Mon Jul 23 08:16:57 PDT 2012


Oh, no. I've accidentally done the *fix*, even though that is contrary
to my own claim.

I don't like the cross-talk of compile-time and run-time variables.
An related issue is bug 3449, but it has been opposed by Walter.

http://d.puremagic.com/issues/show_bug.cgi?id=3449

A small example of bug 3449:
----
void main()
{
    struct Foo1 { const int bar; }
    pragma(msg, Foo1.sizeof);       // Prints "4"

    Foo1 foo1;
    auto p1 = &foo1.bar;            // Succeeds to compile, as excepced.

    struct Foo2 { const int bar = 123; }
    pragma(msg, Foo2.sizeof);       // Prints "1", not "4"

    Foo2 foo2;
    auto p2 = &foo2.bar;    // Error: constant 123 is not an lvalue
}

Why cannot get address of foo2.bar?
The answer is: compiler makes Foo2.bar a manifest constant, because
its type is not mutable and has an initializer.

---

With current dmd, *all* of variable declarations, that has non mutable
type and initializer, are _speculatively_ interpreted in compile time
(== CTFE-ed). If it is succeeds, the declaration will be treated as
same as manifest constant. That is the reason of you explained *bug*
and bug 3449.

I think the *implicit interpretation* is inherited from D1, and if go
back further, will reach to C++ constant variable.
BUT, in D2, we have the 'enum' declaration, which express the
declaration is really manifest constant.

So, the muddy interpretation just confuses many D user's, and less benefit.
I think we should separate run-time variable declarations and compile
time ones, to moderate the leaning curve.

Regards.

Kenji Hara

2012/7/23 bearophile <bearophileHUGS at lycos.com>:
> After a discussion in D.learn started by someone else, after a suggestion of
> mine Timon Gehr has added a bug report:
>
> http://d.puremagic.com/issues/show_bug.cgi?id=8400
>
> But the bug was fixed in the opposite way of what I was thinking.
>
> The problem was that the length of global immutable arrays arrays is seen as
> a compile-time constant.
> Instead of fixing that, Issue 8400 has done the opposite, now even the
> lenght of local immutable arrays is seen sometimes as a compile-time
> constant, and example:
>
>
> int[] foo(in int n) pure nothrow {
>     int[] a;
>     foreach (i; 0 .. n)
>         a ~= i * 10;
>     return a;
> }
> void main() {
>     import core.stdc.stdio: printf;
>     immutable int[] A = foo(5);
>     int[A.length] B;
>     printf("%zd\n", B.length);
> }
>
>
>
> The asm, compiled with -release:
>
> _D4temp3fooFNaNbxiZAi   comdat
> L0:     enter   018h,0
>         push    EBX
>         push    ESI
>         mov dword ptr -018h[EBP],0
>         mov dword ptr -014h[EBP],0
>         mov dword ptr -010h[EBP],0
>         mov -0Ch[EBP],EAX
> L1E:        mov EAX,-010h[EBP]
>         cmp EAX,-0Ch[EBP]
>         jge L48
>         lea ECX,-010h[EBP]
>         mov EDX,[ECX]
>         lea EBX,[EDX*4][EDX]
>         add EBX,EBX
>         push    EBX
>         lea ESI,-018h[EBP]
>         push    ESI
>         mov EAX,offset FLAT:_D11TypeInfo_Ai6__initZ
>         push    EAX
>         call    near ptr __d_arrayappendcT
>         add ESP,0Ch
>         inc dword ptr -010h[EBP]
>         jmp short   L1E
> L48:        mov EDX,-014h[EBP]
>         mov EAX,-018h[EBP]
>         pop ESI
>         pop EBX
>         leave
>         ret
>
> __Dmain comdat
> L0:     enter   018h,0
>         push    EBX
>         push    ESI
>         push    5
>         mov EAX,offset FLAT:_D11TypeInfo_Ai6__initZ
>         push    EAX
>         call    near ptr __d_arrayliteralTX
>         mov dword ptr [EAX],0
>         mov dword ptr 4[EAX],0Ah
>         mov dword ptr 8[EAX],014h
>         mov dword ptr 0Ch[EAX],01Eh
>         mov dword ptr 010h[EAX],028h
>         mov ECX,EAX
>         mov EBX,5
>         lea EDX,-018h[EBP]
>         xor EAX,EAX
>         mov [EDX],EAX
>         mov 4[EDX],EAX
>         mov 8[EDX],EAX
>         mov 0Ch[EDX],EAX
>         mov 010h[EDX],EAX
>         push    5
>         mov ESI,offset FLAT:_DATA
>         push    ESI
>         call    near ptr _printf
>         xor EAX,EAX
>         add ESP,010h
>         pop ESI
>         pop EBX
>         leave
>         ret
>
>
>
> This code too compiles, so A is sometimes computed at run-time and sometimes
> at compile-time:
>
> int[] foo(in int n) pure nothrow {
>     int[] a;
>     foreach (i; 0 .. n)
>         a ~= i * 10;
>     return a;
> }
> void main() {
>     import core.stdc.stdio: printf;
>     int n = 5;
>     immutable int[] A = foo(n);
> }
>
>
>
> Now immutable arrays are sometimes seen as enums. I think this is a problem.
> I think in D compile-time is run only if it's evaluated in a context where
> compile-time values are required. But now the situation is more muddy,
> because knowing n at compile-time is not a way to ask A to be computed at
> compile-time.
>
> Another problem is that compile-time arrays in many situations are not
> efficient, they gets copied every time you use them, and I think that
> __d_arrayliteralTX performs a heap allocation. So now both enum and
> immutable arrays perform heap allocations every time you use them, but only
> in some situations.
>
> I think this is a messy situation, I think the fix for bug 8400 should be
> undone, and I think Issue 8400 should be fixed the other way, turning global
> immutable arrays too into run-time entities.
>
> The bug was fixed by Hara and accepted by Walter, both of them are very
> intelligent, so maybe I am just very wrong :-)
>
> Bye,
> bearophile


More information about the Digitalmars-d mailing list