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

Don Clugston dac at nospam.com
Thu Mar 22 04:14:08 PDT 2012


On 21/03/12 21:41, Alvaro wrote:
> 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*.

Yes, but they read before they write.

> 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