| |
| Posted by Frits van Bommel in reply to bearophile | PermalinkReply |
|
Frits van Bommel
Posted in reply to bearophile
| 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)
|