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