digitalmars.D - Troubles with immutable arrays
- bearophile (115/115) Jul 23 2012 After a discussion in D.learn started by someone else, after a
- kenji hara (37/151) Jul 23 2012 Oh, no. I've accidentally done the *fix*, even though that is contrary
- bearophile (8/8) Jul 23 2012 Thank you for your answer and your understanding, Hara. I hope
- Don Clugston (17/44) Jul 25 2012 Sorry bearophile, I completely disagree with this post.
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
Jul 23 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 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
Jul 23 2012
Thank you for your answer and your understanding, Hara. I hope you will improve the situation. Regarding this issue: http://d.puremagic.com/issues/show_bug.cgi?id=3449 Maybe Walter is wrong about it, so I suggest people to express their opinion. Bye, bearophile
Jul 23 2012
On 23/07/12 15:29, bearophile wrote: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:Sorry bearophile, I completely disagree with this post. Currently, when a compile time value is required, CTFE is attempted. If it fails, an error message is generated. You are asking for a corner case to be introduced. Under certain circumstances (which aren't clearly defined), you want CTFE to *not* be attempted.immutable int[] A = foo(5); int[A.length] B;This code too compiles, so A is sometimes computed at run-time and sometimes at compile-time:immutable int[] A = foo(n);Now immutable arrays are sometimes seen as enums.That is not correct, an immutable array is always different to an enum. For example, an enum is simply a manifest constant, and does not have an address. An immutable array always has an address.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.The only consequence is that if you don't require it at compile time, a particular optimization might not happen. There is no change to semantics.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.That's the famous bug 2356, which is completely irrelevant to this situation.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.Did you even know that initializers of global variables, including arrays, including even mutable arrays, are ALWAYS CTFE'd?
Jul 25 2012