Wrong lowering for a[b][c]++

Alvaro alvaroDotSegura at gmail.com
Wed Mar 21 13:41:10 PDT 2012


El 21/03/2012 19:39, Jonathan M Davis escribió:
> On Wednesday, March 21, 2012 11:29:14 H. S. Teoh wrote:
>> A question was asked on the d-learn forum about why this throws a
>> RangeError:
>>
>> int[string][int] map;
>> map["abc"][20]++;
>>
>> This is understandable, since the compiler translates the second line to:
>>
>> map.opIndex("abc").opIndexUnary!"++"(20);
>>
>> Since map["abc"] doesn't exist yet, opIndex throws RangeError before we
>> ever get to the ++.
>>
>> I'd like to propose the following fix: if a given chained indexing
>> expression has any operator applied to its final result (either a unary
>> operator like ++ or --, or an assignment operator like +=), then instead
>> of translating previous indexes into opIndex, the compiler should map it
>> to a new operator overload, say opIndexCreate, which creates the
>> relevant entry with default value if it doesn't exist yet. That is to
>> say:
>>
>> map["abc"][20]++;
>>
>> should be translated to:
>>
>> map.opIndexCreate("abc").opIndexUnary!"++"(20);
>>
>> where opIndexCreate looks something like:
>>
>> Slot opIndexCreate(Key k) {
>> Slot *s = findSlot(k);
>> if (s is null) {
>> s = createNewSlot(k);
>> }
>> return s;
>> }
>>
>> Similar changes should be made for expressions like a[b][c][d]=100, or
>> a[b][c][d]+=100.
>>
>> In other words, if the tail of a chain of indexing operations maps to
>> opIndexAssign, opIndexUnary, or opIndexOpAssign, then all preceding
>> opIndex calls should be converted to opIndexCreate instead.
>>
>> Comments?
>
> IMHO, it's _horrible_ that C++ creates entries in a std::map when you ask for
> values that aren't there. A RangeError is _exactly_ what should be happening
> here. There's no element to increment, because it hasn't been added yet. I
> think that the current behavior is very much what the behavior _should_ be.
>
> - Jonathan M Davis

I partially disagree. I think items should be added if we try to *write* 
to them, but not when we *read* them (lvalue vs rvalue). The problem is 
that it's hard to distinguish those cases in C++ without an intermediate 
class that makes its use uglier. So:

int[int] a;
a[3] = 1; // OK, add key 3
b = a[5]; // error, add nothing

And, compound assignment and increment/decrement are forms of *writing*. 
So, they should trigger an element creation with the .init value.

a[5]++; // create a[5] = int.init; and then increment


More information about the Digitalmars-d mailing list