www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Wrong lowering for a[b][c]++

reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
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?


T

-- 
One Word to write them all, One Access to find them, One Excel to count them
all, And thus to Windows bind them. -- Mike Champion
Mar 21 2012
next sibling parent "David Nadlinger" <see klickverbot.at> writes:
On Wednesday, 21 March 2012 at 18:27:30 UTC, 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]++;

Wait a second – aren't AAs _supposed_ to throw if accessing a key that doesn't exist yet? To be able to increment something, there already has to be a value to start from… David
Mar 21 2012
prev sibling next sibling parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 03/21/2012 11:29 AM, 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]++;

Hey! That syntax is following the broken syntax of C and C++. ;) This works: import std.stdio; void main() { int[string][int] map; map[20]["abc"]++; writeln(map); } The output: [20:["abc":1]] Ali
Mar 21 2012
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 3/21/12, Ali =C7ehreli <acehreli yahoo.com> wrote:
 This works:

For some reason thought it didn't work without double-checking. Heh. :p
Mar 21 2012
prev sibling next sibling parent "Jesse Phillips" <Jessekphillips+D gmail.com> writes:
H. S. is making a Library replacement AA and is what his example 
is concerned with.

You are correct, it seems his example has it out of order, the 
example on Learn was

int[100][string] map;
...

On Wednesday, 21 March 2012 at 18:58:34 UTC, Ali Çehreli wrote:
 This works:

 import std.stdio;

 void main()
 {
     int[string][int] map;
     map[20]["abc"]++;

     writeln(map);
 }

 The output:

 [20:["abc":1]]

 Ali

Mar 21 2012
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 21 Mar 2012 14:29:14 -0400, H. S. Teoh <hsteoh quickfur.ath.cx>  
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 ++.

What about a create accessor of the map which is the same as accessing the map, except it ensures T.init is used at each level? That is: map.create["abc"][20]++; Whether you want default-created elements or not is an important design decision that should not be up to the container. -Steve
Mar 21 2012
prev sibling parent Alvaro <alvaroDotSegura gmail.com> writes:
El 21/03/2012 19:29, H. S. Teoh escribi:
 A question was asked on the d-learn forum about why this throws a
 RangeError:

 	int[string][int] map;
 	map["abc"][20]++;

IIRC, that worked fine for me a few weeks ago. And I found it to be just great that it did. I'll have to re-check but I remember it like this. I had to produce a new tabular dataset from an original by accumulating elements (rows) sharing some attribute values. The idea was to read that line by line, split into attributes and do: // this will hold the counts: int[int][int][int][string] count; // for each row, split field1 .. field5 (field4 is a string) count[field1][field2][field3][field4] += field5; And that just worked IIRC, without initializing anything! At the end, to iterate all the hyper map and write it out, we used nested foreachs, something like: foreach(field1, item1; count) foreach(field2, item2; item1) foreach(field3, item3; item2) foreach(field4, field5; item3) writeln(field1, field2, field3, field4, field5); I'm trying to remember if we had to do something special to make it work...
Mar 21 2012