Alex Rivera | Logout

Why can't I store string keys in an Associative Array?

Asked 2011-01-06T03:30:42.577
17

I'm new to D programming language, just started reading The D Programming Language book.

I run into error when trying one associative array example code

#!/usr/bin/rdmd
import std.stdio, std.string;

void main() {
    uint[string] dict;
    foreach (line; stdin.byLine()) {
        foreach (word; splitter(strip(line))) {
            if (word in dict) continue;
            auto newId = dict.length;
            dict[word] = newId;
            writeln(newId, '\t', word);
        }   
    }   
}

DMD shows this Error message:

./vocab.d(11): Error: associative arrays can only be assigned values with immutable keys, not char[]

I'm using DMD compile 2.051

I was guessing the rules for associative arrays has changed since the TDPL book.

How should I use Associative arrays with string keys?

Thanks.

Update:

I found the solution in later parts of the book.

use string.idup to make a duplicate immutable value before putting into the array.

so

dict[word.idup] = newId;

would do the job.

But is that efficient ?

Edit
Report

1 Answer

26

Associative arrays require that their keys be immutable. It makes sense when you think about the fact that if it's not immutable, then it might change, which means that its hash changes, which means that when you go to get the value out again, the computer won't find it. And if you go to replace it, you'll end up with another value added to the associative array (so, you'll have one with the correct hash and one with an incorrect hash). However, if the key is immutable, it cannot change, and so there is no such problem.

Prior to dmd 2.051, the example worked (which was a bug). It has now been fixed though, so the example in TDPL is no longer correct. However, it's not so much the case that the rules for associative arrays have changed as that there was a bug in them which was not caught. The example compiled when it shouldn't have, and Andrei missed it. It's listed in the official errata for TDPL and should be fixed in future printings.

The corrected code should use either dictionary[word.idup] or dictionary[to!string(word)]. word.idup creates a duplicate of word which is immutable. to!string(word), on the other hand converts word to a string in the most appropriate manner. As word is a char[] in this case, that would be to use idup. However, if word were already a string, then it would simply return the value which was passed in and not needlessly copy it. So, in the general case, to!string(word) is the better choice (particularly in templated functions), but in this case, either works just fine (to!() is in std.conv).

It is technically possible to cast a char[] to a <

answered 2011-01-06T05:43:35.387

Your Answer