Should range foreach be iterating over an implicit copy?

Nick Sabalausky SeeWebsiteToContactMe at semitwist.com
Wed May 16 22:48:06 PDT 2012


I'm a little discouraged that my concern about "input ranges can't save 
their state, and yet that's exactly what happens implicitly" hasn't been 
addressed. I was hoping to at least get a "That's not really a problem and 
here's why..."

However, that said...

"Andrei Alexandrescu" wrote...
> It is deliberate and the intent is that millions of programmers used to 
> foreach from other languages don't scream "where is my range???"

"Era Scarecrow" wrote...
> Range can refer to many things, and I'm assuming array is one of them. 
> So... If the array is consumed when using foreach, that seems dumb right? 
> (An array in the end is just a small struct afterall...)

I admit, those are fair points.

With those in mind, I've given it some more thought, and here are my 
current...umm...thoughts:

- 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.




More information about the Digitalmars-d mailing list