Issue 4279 - [AA] AAs change key type
Summary: [AA] AAs change key type
Status: NEW
Alias: None
Product: D
Classification: Unclassified
Component: druntime (show other issues)
Version: D2
Hardware: x86 Windows
: P3 normal
Assignee: Sean Kelly
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-06-06 04:54 UTC by bearophile_hugs
Modified: 2024-12-07 13:31 UTC (History)
4 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description bearophile_hugs 2010-06-06 04:54:52 UTC
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 Andrej Mitrovic 2010-08-29 21:07:55 UTC
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 Steven Schveighoffer 2010-08-30 06:18:44 UTC
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 Andrej Mitrovic 2010-08-30 06:47:23 UTC
(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 Steven Schveighoffer 2010-08-30 06:57:47 UTC
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 hsteoh 2012-02-27 17:34:23 UTC
const handling in AA's is badly broken; see bug 7512.
Comment 6 dlangBugzillaToGithub 2024-12-07 13:31:01 UTC
THIS ISSUE HAS BEEN MOVED TO GITHUB

https://github.com/dlang/dmd/issues/17226

DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB