Should range foreach be iterating over an implicit copy?

Erik Jensen eriksjunk at rkjnsn.net
Thu May 17 16:04:35 PDT 2012


On Thursday, 17 May 2012 at 05:48:44 UTC, Nick Sabalausky wrote:
> - A range is not a collection, it's a *view* of a collection 
> (or of
> something else). This is a necessary distinction because ranges 
> and
> collections work in fundamentally different ways: A range is, 
> *by necessity*
> consumed as it's iterated - that's what popFront *does*, that's
> fundamentally how ranges work. For many collections, OTOH, it 
> makes *no*
> sense to consume the collection while iterating it. Thus, range 
> !=
> collection, it's a view of a collection.
>
> - Ranges are D's answer to iterators. I don't think people used 
> to iterators
> from other languages would expect their iterator to magically 
> reset itself
> after being used. So I see no reason why they would expect a 
> range (ie, an
> iterator-pair-with-benefits) to behave differently than that.
>
> - D's arrays conflate the ideas of "collection" and "range", 
> hence the odd
> edge case Era pointed out, and hence the "need" for foreach to 
> automatically
> make a copy. But in my (not super-extensive) experience 
> creating ranges,
> I've found that to be a problematic pattern (due to the 
> fundamental
> distinction between a range and a collection), and learned to 
> prefer making
> my iterable things *return* a range, rather than actually *be* 
> ranges.
>
> - Admittedly, it would be annoying if foreach had to be used 
> like this on
> all collections: "foreach(e; myArray.rangeOf)", so I guess it 
> would make
> sense for a range to automatically be obtained when foreach-ing 
> over a
> collection. However, I'm still not 100% sold on the current 
> method of doing
> that (making foreach automatically copy struct-based ranges), 
> partly because
> of the questionable implications it has for input ranges, and 
> partly because
> (for struct-ranges) it leaves no way to access the range that's 
> actually
> being iterated.
>
> - At the very least, perhaps input ranges just shouldn't be 
> allowed to be
> structs? After all, structs are intended to be copied around, 
> but input
> ranges, by definition, can't have their current state copied.

I would be very much in support of having ranges and containers 
be distinct, with a standard way to get a range from a container. 
Something very similar is done in C#, where containers have a 
getEnumerator() method. The enumerator itself has a Current 
property and moveNext method (similar to front and popFront of a 
range), and thus is consumed as you use it. In my experience, 
this system works very well.

Another advantage of giving arrays a method to obtain a range 
instead of them being a range themselves is that using foreach on 
a const/immutable array would work as expected without having to 
perform a slice to make it work. I would even go so far as to say 
that having an array BE a range really doesn't make any sense, 
conceptually.


More information about the Digitalmars-d mailing list