Associative Array .byKey / .byValue: Counter and Tuples

Mike Parker via Digitalmars-d digitalmars-d at puremagic.com
Sun Apr 3 04:17:17 PDT 2016


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.




More information about the Digitalmars-d mailing list