www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Associative Array .byKey / .byValue: Counter and Tuples

reply Q. Schroll <qs.il.paperinik gmail.com> writes:
Simple as that, suppose
     uint[uint] aa;
Any range supports carrying an index. Not so does the Range 
returned by byKey and byValue.
     foreach (i, k; aa.byKey) { }
and
     foreach (i, v; aa.byValue) { }
both don't compile.

Reason (I found out by chance):

If the key or value type is a std.typecons.Tuple, iteration over 
aa.by* decomposes the Tuple if there is the right number of 
arguments. For 2-Tuples, there cannot be both possible.

     alias Tup = Tuple!(int, int);
     int[Tup] it;
     Tup[int] ti;

     foreach (x, y; it.byKey) { }
     foreach (x, y; ti.byValue) { }

Why is this undocumented? http://dlang.org/spec/hash-map.html 
doesn't mention Tuples at all!
Why is this useful? Anyone can decompose the Tuple with .expand 
if they like. I would prefer allowing an index.

If it does not meet the spec, is it a bug then?
Apr 03 2016
parent reply Mike Parker <aldacron gmail.com> writes:
On Sunday, 3 April 2016 at 10:59:47 UTC, Q. Schroll wrote:
 Simple as that, suppose
     uint[uint] aa;
 Any range supports carrying an index. Not so does the Range 
 returned by byKey and byValue.
     foreach (i, k; aa.byKey) { }
 and
     foreach (i, v; aa.byValue) { }
 both don't compile.
That's incorrect. Only Random Access Ranges are indexable. The ranges returned by aa.byKey and aa.byValue are simply Input Ranges. Moreover, ranges do not by default allow for an index value in a foreach loop. That only works out of the box with arrays. To get the same for a range, you can use std.range.enumerate: import std.range : enumerate; foreach(i, k; aa.byKey.enumerate) {}
 Reason (I found out by chance):

 If the key or value type is a std.typecons.Tuple, iteration 
 over aa.by* decomposes the Tuple if there is the right number 
 of arguments. For 2-Tuples, there cannot be both possible.

     alias Tup = Tuple!(int, int);
     int[Tup] it;
     Tup[int] ti;

     foreach (x, y; it.byKey) { }
     foreach (x, y; ti.byValue) { }

 Why is this undocumented? http://dlang.org/spec/hash-map.html 
 doesn't mention Tuples at all!
D's associative arrays don't know anything about Tuples, so there's no reason for the aa docs to talk about them. This behavior comes from how std.typecons.Tuple is implemented.
 Why is this useful? Anyone can decompose the Tuple with .expand 
 if they like. I would prefer allowing an index.
If you look at the source of Tuple, alias this is used on .expand, which is likely why they are automatically decomposed in an aa.
Apr 03 2016
parent Q. Schroll <qs.il.paperinik gmail.com> writes:
On Sunday, 3 April 2016 at 11:17:17 UTC, Mike Parker wrote:
 On Sunday, 3 April 2016 at 10:59:47 UTC, Q. Schroll wrote:
 Simple as that, suppose
     uint[uint] aa;
 Any range supports carrying an index. Not so does the Range 
 returned by byKey and byValue.
     foreach (i, k; aa.byKey) { }
 and
     foreach (i, v; aa.byValue) { }
 both don't compile.
That's incorrect. Only Random Access Ranges are indexable. The ranges returned by aa.byKey and aa.byValue are simply Input Ranges. Moreover, ranges do not by default allow for an index value in a foreach loop. That only works out of the box with arrays.
It looks like I've used Random Access Ranges so far (without realizing that matters that much).
 To get the same for a range, you can use std.range.enumerate:

 import std.range : enumerate;
 foreach(i, k; aa.byKey.enumerate) {}
Thanks. That solves the problem.
 Reason (I found out by chance):

 If the key or value type is a std.typecons.Tuple, iteration 
 over aa.by* decomposes the Tuple if there is the right number 
 of arguments. For 2-Tuples, there cannot be both possible.

     alias Tup = Tuple!(int, int);
     int[Tup] it;
     Tup[int] ti;

     foreach (x, y; it.byKey) { }
     foreach (x, y; ti.byValue) { }

 Why is this undocumented? http://dlang.org/spec/hash-map.html 
 doesn't mention Tuples at all!
D's associative arrays don't know anything about Tuples, so there's no reason for the aa docs to talk about them. This behavior comes from how std.typecons.Tuple is implemented.
 Why is this useful? Anyone can decompose the Tuple with 
 .expand if they like. I would prefer allowing an index.
If you look at the source of Tuple, alias this is used on .expand, which is likely why they are automatically decomposed in an aa.
I know about the alias expand this in Tuple, but simply didn't expect it can go that far. On the other hand, it sounds plausible. I never expected a special preference of AAs for Tuples. It's very interesting that alias this can work like this.
Apr 03 2016