www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Inserting to associative array do not return a lvalue.

reply Yang Bo <pop.atry gmail.com> writes:
I tend to write code like this:

int[int] a;
int* r = &(a[1] = 2); // error
(*r)++;

The problem is, `a[1] = 2` does not return a lvalue. I must write:

int[int] a;
a[1] = 2;
int* r = a[1];
(*r)++;

I have to look up the associative array twice, this is unwanted cost.
Oct 16 2007
parent reply Yang Bo <pop.atry gmail.com> writes:
Sorry. I thought I have a mistake. Holding a pointer to the value of an
associative array is very dangerious.Yang Bo д:
 I tend to write code like this:
 
 int[int] a;
 int* r = &(a[1] = 2); // error
 (*r)++;
 
 The problem is, `a[1] = 2` does not return a lvalue. I must write:
 
 int[int] a;
 a[1] = 2;
 int* r = a[1];
 (*r)++;
 
 I have to look up the associative array twice, this is unwanted cost.

Oct 16 2007
next sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Yang Bo wrote:
 Sorry. I thought I have a mistake. Holding a pointer to the value of an
 associative array is very dangerious.Yang Bo д:
 I tend to write code like this:

 int[int] a;
 int* r = &(a[1] = 2); // error
 (*r)++;

 The problem is, `a[1] = 2` does not return a lvalue. I must write:

 int[int] a;
 a[1] = 2;
 int* r = a[1];
 (*r)++;

 I have to look up the associative array twice, this is unwanted cost.


If you really want to be able to do things like that, there are Map container classes out there that will allow it. But modifying pointers to _keys_ is always a no-no. Some places you can find a Map class: Tango, Arclib, OpenMesh/D, Juno, Stewart's Utility Library --bb
Oct 16 2007
prev sibling parent reply BCS <ao pathlink.com> writes:
Reply to Yang,

 Sorry. I thought I have a mistake. Holding a pointer to the value of
 an associative array is very dangerious.Yang Bo ??:
 

this works int[int] a; a[1] = 2; int* r = 1 in a; (*r)++; assert(2 == a[1]);
Oct 16 2007
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
BCS wrote:
 Reply to Yang,
 
 Sorry. I thought I have a mistake. Holding a pointer to the value of
 an associative array is very dangerious.Yang Bo ??:

this works int[int] a; a[1] = 2; int* r = 1 in a; (*r)++; assert(2 == a[1]);

Yeh, I don't think there's anything wrong with modifying the value. But your version does two lookups also. Yang makes a good point. The AA *has* a pointer to the node it just inserted, it just doesn't return it (or a pointer to the value). Compare with STL map where the insert function returns an iterator to the inserted node. Really the problem is that D doesn't have a reference type constructor (just a parameter storage class). In a D-with-references world, a[1] = 2 would return a reference to the value instead of a copy. Another possible solution would be to require all pointer arithmetic to use an explicit &, similar to how function pointers work in D. Then a plain Foo* would be able act like basically like a reference, and a[1] = 2 could happily return a pointer. But that's probably too big a change to happen now. And probably too confusing for C/C++ folks, anyway. Foo *foo; foo = 3; // huh? --bb
Oct 16 2007
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Bill Baxter" wrote
 BCS wrote:
 Reply to Yang,

 Sorry. I thought I have a mistake. Holding a pointer to the value of
 an associative array is very dangerious.Yang Bo ??:

this works int[int] a; a[1] = 2; int* r = 1 in a; (*r)++; assert(2 == a[1]);

Yeh, I don't think there's anything wrong with modifying the value. But your version does two lookups also. Yang makes a good point. The AA *has* a pointer to the node it just inserted, it just doesn't return it (or a pointer to the value). Compare with STL map where the insert function returns an iterator to the inserted node. Really the problem is that D doesn't have a reference type constructor (just a parameter storage class). In a D-with-references world, a[1] = 2 would return a reference to the value instead of a copy. Another possible solution would be to require all pointer arithmetic to use an explicit &, similar to how function pointers work in D. Then a plain Foo* would be able act like basically like a reference, and a[1] = 2 could happily return a pointer. But that's probably too big a change to happen now. And probably too confusing for C/C++ folks, anyway. Foo *foo; foo = 3; // huh? --bb

Technically, the extra lookup isn't very costly. Most likely you add keys rarely. To make the code more optimized, you would do something like: int *r = null; if(!(r = 1 in a)) { a[1] = 0; r = 1 in a; } *r = 2; (*r)++; This allows you to avoid the extra lookup (actually extra 2 lookups) if the node already exists, which should be the more common case. If you analyze it in big-O notation, the extra-lookup factor is really only a constant, and so the complexity is the same. However, we already have properties on AA's that are built into the language. Would it not make sense to do this as a property? e.g.: int *r = a.setval(1, 2); (*r)++; Due to the way functions on arrays can be used as properties, you could even have: int *setval(int[int] arr, int key, int val) { int *r = key in arr; if(!r) // triple lookup only on first call to setval { arr[key] = val; r = key in arr; } else *r = val; return r; } This can be done without augmenting the language spec, although it still has the triple lookup cost on the first call which could be avoided if it was done in the language itself. I'm sure someone out there can templatize this :) -Steve
Oct 16 2007
parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Steven Schveighoffer wrote:
 "Bill Baxter" wrote
 BCS wrote:
 Reply to Yang,


Technically, the extra lookup isn't very costly. Most likely you add keys rarely. To make the code more optimized, you would do something like: int *r = null; if(!(r = 1 in a)) { a[1] = 0; r = 1 in a; } *r = 2; (*r)++; This allows you to avoid the extra lookup (actually extra 2 lookups) if the node already exists, which should be the more common case. If you analyze it in big-O notation, the extra-lookup factor is really only a constant, and so the complexity is the same. However, we already have properties on AA's that are built into the language. Would it not make sense to do this as a property? e.g.: int *r = a.setval(1, 2); (*r)++; Due to the way functions on arrays can be used as properties, you could even have: int *setval(int[int] arr, int key, int val) { int *r = key in arr; if(!r) // triple lookup only on first call to setval { arr[key] = val; r = key in arr; } else *r = val; return r; } This can be done without augmenting the language spec, although it still has the triple lookup cost on the first call which could be avoided if it was done in the language itself. I'm sure someone out there can templatize this :)

I'd also like to have Python's pop,popitem,get,setdefault, and update functions built-in. Or at least defined in a std.something. --bb
Oct 16 2007