https://issues.dlang.org/show_bug.cgi?id=7753
--- Comment #8 from Steven Schveighoffer <[email protected]> --- Just wanted to post something here. The call a[b][c][d] = 0 results in different calls (_aaGetY now) than x = a[b][c][d] (_aaGetRvalueX). So I think H S Teoh is onto the right path. Having a different opIndex available for assignment (or lvalue manipluation) makes sense and should be straightforward to define. Now, to define this a little more concretely, I think opIndexCreate should ONLY be used when the entire chain of indexing results in a definite lvalue requirement. This means ONLY opIndexCreate (or AA usage) available in the expression, and the final "call" should be an opAssign or opOpAssign or opIndexOpAssign. I would also throw in opUnary that expects mutation (i.e. ++ or --) because it's currently supported by AAs. Unfortunately, the existing behavior is somewhat inconsistent: struct S { int x; void opUnary(string s : "++")() {++x;} } S[int][int] aa; aa[1][1] = S(1); // ok aa[2][2].x = 5; // range violation ++aa[3][3]; // range violation int[int] aa2; aa2[4] += 3; // ok ++aa2[5]; // ok void foo(ref int x) foo(aa2[6]); // range violation So there is not 100% consistency here. The most rational logical implementation would just require lvalue usage. But the reality is different. Also note that ++aa[5] does not match ANY operator that would be on the type of aa. There is no opIndexOpUnary akin to opIndexOpAssign. And it doesn't work if your underlying type supports ++. That is an inconsistency that will be tough to duplicate. --
