www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Problem with AAs and ?:

reply bearophile <bearophileHUGS lycos.com> writes:
Can someone explain me where such difference comes from?
Is this a bug?

import std.stdio: writefln;

void main() {
    string[] words = ["how", "are", "you", "are"];

    int[string] aa1;
    foreach (w; words)
        aa1[w] = ((w in aa1) ? (aa1[w] + 1) : 2);
    writefln(aa1); // Prints: [how:1,you:1,are:2]

    int[string] aa2;
    foreach (w; words)
        if (w in aa2)
            aa2[w]++;
        else
            aa2[w] = 2;
    writefln(aa2); // Prints: [how:2,you:2,are:3]
}

Bye,
bearophile
Mar 08 2008
next sibling parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"bearophile" <bearophileHUGS lycos.com> wrote in message 
news:fqu9np$27ic$1 digitalmars.com...
 Can someone explain me where such difference comes from?
 Is this a bug?

 import std.stdio: writefln;

 void main() {
    string[] words = ["how", "are", "you", "are"];

    int[string] aa1;
    foreach (w; words)
        aa1[w] = ((w in aa1) ? (aa1[w] + 1) : 2);
    writefln(aa1); // Prints: [how:1,you:1,are:2]

    int[string] aa2;
    foreach (w; words)
        if (w in aa2)
            aa2[w]++;
        else
            aa2[w] = 2;
    writefln(aa2); // Prints: [how:2,you:2,are:3]
 }

This is odd. Change the body of the first loop to: auto val = (w in aa1) ? (aa1[w] + 1) : 2; aa1[w] = val; And they both output the same thing (2, 2, 3). Sorry, breakfast time, I'll look at it a bit more afterwards ;)
Mar 08 2008
prev sibling parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
bearophile wrote:
 Can someone explain me where such difference comes from?
 Is this a bug?
 
 import std.stdio: writefln;
 
 void main() {
     string[] words = ["how", "are", "you", "are"];
 
     int[string] aa1;
     foreach (w; words)
         aa1[w] = ((w in aa1) ? (aa1[w] + 1) : 2);
     writefln(aa1); // Prints: [how:1,you:1,are:2]
 
     int[string] aa2;
     foreach (w; words)
         if (w in aa2)
             aa2[w]++;
         else
             aa2[w] = 2;
     writefln(aa2); // Prints: [how:2,you:2,are:3]
 }

I looked at the generated code, and it seems that for AA insertions the compiler generates calls an internal routine (_aaGet) which returns a pointer to the location to put the value into (instead of inserting it directly). And that call is made *before* the new value is evaluated. The result is that (w in aa1) evaluates to true because in order to be able to return that pointer the _aaGet routine allocates the relevant AA cell if it doesn't exist already; so by the time 'in' is evaluated there is indeed such a key present (its value just hasn't been set yet). Essentially, the left side of the assignment is evaluated before the right side is. I don't think this is technically a compiler bug with the current the specification; '=' doesn't determine order of evaluation AFAICT, so the compiler would seem to have every right to evaluate the left-hand-side first. That's probably not what most users would expect, but I can see why this is done. The combination of evaluating the right-hand-side of the assignment and writing it to the AA can in certain situations be more efficient if it's possible to write the value directly into the AA. (For example: "big" structs returned from functions are normally written to a caller-specified address so by evaluating the target location first "aa[key] = foo()" can pass the AA cell address to the function, which avoids an extra copy of the struct)
Mar 08 2008
parent bearophile <bearophileHUGS lycos.com> writes:
Frits van Bommel:
 I don't think this is technically a compiler bug with the current the 
 specification; '=' doesn't determine order of evaluation AFAICT,

Even if technically it's not a compiler bug, it's seems a bug to me. I like D because it has less surprises than C++. To me a bit less (how much?) running speed is acceptable if similar bugs are avoided by my code. Bye and thank you, bearophile
Mar 08 2008