Comment #0 by bearophile_hugs — 2010-06-06T04:54:52Z
With DMD v2.046 this program prints const(char)[] instead of char[]
import std.stdio: writeln;
void main() {
int[char[]] data = [cast(char[])"foo" : 1];
foreach (key, val; data)
writeln(typeid(typeof(key)));
}
Modifying AA keys after they are inserted in the AA is indeed bad because their hash value and position inside the AA doesn't get recomputed.
But the current design/behaviour is surprising and bad, because I have asked for a key type and the runtime/compiler gives me a different key type (forcing me to use casts). There are two possible behaviours that I see acceptable here:
1) to disallow AAs with mutable keys, their literals and definition too (as Python does), so in this case this variable definition becomes a compile-time error:
int[int[]] data;
2) or to allow mutable keys (and hope the programmer will not mutate them) (as I think D1 does), and keep their type unchanged (mutable).
Comment #1 by andrej.mitrovich — 2010-08-29T21:07:55Z
As of 2.048, and according to my tests, DMD forces AA's to have a const type as the key type. For example:
import std.stdio: writeln;
void main()
{
int[int[]] data;
writeln(typeid(data));
}
Prints: int[const(int)[]]
And your AA literal key type gets converted to a const type as well:
import std.stdio: writeln;
void main()
{
writeln(typeid([cast(char[])"foo" : 1]));
}
Prints: int[const(char)[]]
What happens here (if my interpretation is right), is that foo is first an array of immutable chars, it's casted to a mutable array of chars, and then DMD sees it is a key of an AA literal so it converts it to an array of const chars.
So DMD is most probably doing this:
On the left of assignment:
int[char[]] data
-> int[const(char)[]] data
On the right of assignment:
[cast(char[])const(char)[] : int]
-> int[cast(char[])const(char)[]]
-> int[char[]]
-> int[const(char)[]]
And the whole thing becomes:
int[const(char)[]] data = int[const(char)[]]
So if I got that right then DMD automatically changes the key type of an AA to be const, regardless of any casts. Having to change int[] to const(int)[] directly in the code would probably make the AA's harder to read, so maybe that's a good thing.
Comment #2 by schveiguy — 2010-08-30T06:18:44Z
I think changing the key type to const during iteration is a useless gesture, and just serves as an annoyance rather than a guarantee.
See bug 4410 that I reported later but for a different reason.
Comment #3 by andrej.mitrovich — 2010-08-30T06:47:23Z
(In reply to comment #2)
> I think changing the key type to const during iteration is a useless gesture,
> and just serves as an annoyance rather than a guarantee.
>
> See bug 4410 that I reported later but for a different reason.
In this case it doesn't change the key type during iteration, it changes it in the declaration:
import std.stdio: writeln;
void main()
{
int[char[]] data = [cast(char[])"foo" : 1];
writeln(typeid(data));
}
Prints: int[const(char)[]]
Unless I got it wrong here. :)
Comment #4 by schveiguy — 2010-08-30T06:57:47Z
Oh, I didn't notice that.
I was looking at bearophile's code.
But my point is the same -- converting to const does not guarantee anything. In reality, the only place where you are affected is during iteration, as everywhere else, the key is an input.
Comment #5 by hsteoh — 2012-02-27T17:34:23Z
const handling in AA's is badly broken; see bug 7512.
Comment #6 by robert.schadek — 2024-12-07T13:31:01Z