May 17, 2012
On Thursday, May 17, 2012 11:05:46 Steven Schveighoffer wrote:
> Hm... proposal:
> 
> foreach(e; ref r)
> {
> }
> 
> equates to your desired code.  Would this help?

Or you could just do

for(; !r.empty; r.popFront())
{
    auto e = r.front;
}

I really don't think that that's a big deal. I don't think that the language change would be worth having yet another thing in the language to remember, particularly when it's so easy to just use for to do the job.

- Jonathan M Davis
May 17, 2012
On Thu, 17 May 2012 11:42:04 -0400, Jonathan M Davis <jmdavisProg@gmx.com> wrote:

> On Thursday, May 17, 2012 11:05:46 Steven Schveighoffer wrote:
>> Hm... proposal:
>>
>> foreach(e; ref r)
>> {
>> }
>>
>> equates to your desired code.  Would this help?
>
> Or you could just do
>
> for(; !r.empty; r.popFront())
> {
>     auto e = r.front;
> }
>
> I really don't think that that's a big deal. I don't think that the language
> change would be worth having yet another thing in the language to remember,
> particularly when it's so easy to just use for to do the job.

Probably true.  The only one I'd see as being impossible to duplicate is:

foreach(ref e; ref r)

-Steve
May 17, 2012
On Thursday, May 17, 2012 13:23:22 Steven Schveighoffer wrote:
> On Thu, 17 May 2012 11:42:04 -0400, Jonathan M Davis <jmdavisProg@gmx.com>
> 
> wrote:
> > On Thursday, May 17, 2012 11:05:46 Steven Schveighoffer wrote:
> >> Hm... proposal:
> >> 
> >> foreach(e; ref r)
> >> {
> >> }
> >> 
> >> equates to your desired code. Would this help?
> > 
> > Or you could just do
> > 
> > for(; !r.empty; r.popFront())
> > {
> > 
> > auto e = r.front;
> > 
> > }
> > 
> > I really don't think that that's a big deal. I don't think that the
> > language
> > change would be worth having yet another thing in the language to
> > remember,
> > particularly when it's so easy to just use for to do the job.
> 
> Probably true. The only one I'd see as being impossible to duplicate is:
> 
> foreach(ref e; ref r)

But that only works if front returns a ref. If it doesn't, the ref would be to a local variable (so I don't know if that even compiles). And if front returns a ref, all you have to do is use front instead of e. So, no it wouldn't be _identical_, but close enough.

- Jonathan M Davis
May 17, 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.
May 18, 2012
On Friday, May 18, 2012 01:04:35 Erik Jensen wrote:
> 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.

opSlice is the standard way to return a range from a container.

- Jonathan M Davis
May 18, 2012
On Thursday, 17 May 2012 at 14:18:55 UTC, Steven Schveighoffer wrote:
> [...]  I believe someone has created a byRef struct that wraps a range and iterates it byRef (maybe dsimcha?)

Nope, me. :)

https://github.com/kyllingstad/ltk/blob/master/ltk/range.d#L12

It only supports the input range primitives, because that was all I needed when I wrote it.  I offered to contribute it to Phobos (with support for the remaining range types, of course), but the interest for it seemed rather low.

-Lars
June 07, 2012
On Wednesday, 16 May 2012 at 21:40:39 UTC, Andrei Alexandrescu wrote:
> On 5/16/12 4:37 PM, Nick Sabalausky wrote:
>> One counter-argument that was raised is that TDPL has an example on page 381
>> that indicates foreach iterates over an implicit copy. I don't have a copy
>> handy ATM, so I can't look at it myself, but I'd love to see Andrei weigh in
>> on this: I'm curious if this example in TDPL made that copy deliberately, or
>> if the full implications of that copy were just an oversight.
>
> It is deliberate and the intent is that millions of programmers used to foreach from other languages don't scream "where is my range???"
>
> Andrei

According to the docs, however, an InputRange that is not a ForwardRange won't necessarily behave the way millions of programers used to foreach from other languages expect them to.  Such an operation will most likely consume the underlying data, whether foreach makes an implicit copy or not.

Put another way, whether a non-ForwardRange is consumed by a foreach the way it currently works is unspecified.

The docs also say that the right way to checkpoint a ForwardRange is by calling save().

This tells me that the most intuitive way for foreach to work is:

a. If it's a ForwardRange, make a copy with save(), then consume the copy.
b. If it's not a ForwardRange, consume the original.
June 08, 2012
On Friday, 18 May 2012 at 06:17:13 UTC, Lars T. Kyllingstad wrote:
> On Thursday, 17 May 2012 at 14:18:55 UTC, Steven Schveighoffer wrote:
>> [...]  I believe someone has created a byRef struct that wraps a range and iterates it byRef (maybe dsimcha?)
>
> Nope, me. :)
>
> https://github.com/kyllingstad/ltk/blob/master/ltk/range.d#L12
>
> It only supports the input range primitives, because that was all I needed when I wrote it.  I offered to contribute it to Phobos (with support for the remaining range types, of course), but the interest for it seemed rather low.
>
> -Lars

I've got a use for it right now.  I've implemented groupBy for my project, which is like std.algorithm.group except that instead of giving you the number of adjacent equivalent items, it gives you a lazy subrange of them.  So you end up with a range of subranges.

Trouble is, if you feed the inner range to foreach, it works on a copy of the inner range.  Which means that the outer range skips through the entire inner range you just iterated through in order to get to the next inner range.

Now if the range you feed to groupBy is a true non-ForwardRange, where copying it just creates an alias of some kind, this problem goes away.  Your wrapper looks like it would do the trick there.

At any rate, the whole thing makes an excellent use case for foreach(ref e; ref r).
1 2
Next ›   Last »