www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Consevutive calls to r.front

reply "Mike Parker" <aldacron gmail.com> writes:
When implementing a custom range, is it correct to say that 
consecutive calls to r.front with no intervening calls to 
popFront should return the same value? Seems like I read 
something along those lines before, but I can't find it anywhere.
Jun 07 2015
next sibling parent reply "Dennis Ritchie" <dennis.ritchie mail.ru> writes:
On Monday, 8 June 2015 at 00:42:12 UTC, Mike Parker wrote:
 When implementing a custom range, is it correct to say that 
 consecutive calls to r.front with no intervening calls to 
 popFront should return the same value?
Yes. For examle: import std.stdio, std.range; template foo(T) { auto foo(R)(R range) { while (!range.empty) { writeln(range.front); // .front --> the first element of the range range.popFront; // .popFront --> to extract the first element of the range } } } void main() { foo!(int[])([1, 2, 3]); }
Jun 07 2015
next sibling parent "Dennis Ritchie" <dennis.ritchie mail.ru> writes:
The foreach loop takes place in a for loop like this:

import std.range;

for (auto __c = 5.iota; !__c.empty; __c.popFront) {
	auto elem = __c.front;
}
Jun 07 2015
prev sibling parent reply Mike Parker <aldacron gmail.com> writes:
On 6/8/2015 9:55 AM, Dennis Ritchie wrote:
 On Monday, 8 June 2015 at 00:42:12 UTC, Mike Parker wrote:
 When implementing a custom range, is it correct to say that
 consecutive calls to r.front with no intervening calls to popFront
 should return the same value?
Yes. For examle: import std.stdio, std.range; template foo(T) { auto foo(R)(R range) { while (!range.empty) { writeln(range.front); // .front --> the first element of the range range.popFront; // .popFront --> to extract the first element of the range } } } void main() { foo!(int[])([1, 2, 3]); }
I know how to use a range :) What I'm asking about is a requirement on implementing front on a custom range. Is there a rule that says when I implement my own range, consecutive calls to front must return the same value until popFront is called? Example: Is this a valid implementation of front? auto front() { return _member++; } Or must it be this: auto front() { return _member; } void popFront() { ++_member; } My current understanding is that the former is incorrect, but I'm looking for confirmation of that. I can't find it written down anywhere.
Jun 07 2015
parent reply "Dennis Ritchie" <dennis.ritchie mail.ru> writes:
On Monday, 8 June 2015 at 01:15:30 UTC, Mike Parker wrote:
 I know how to use a range :) What I'm asking about is a 
 requirement on implementing front on a custom range. Is there a 
 rule that says when I implement my own range, consecutive calls 
 to front must return the same value until popFront is called?

 Example:
 Is this a valid implementation of front?
 auto front() { return _member++; }

 Or must it be this:
 auto front() { return _member; }
 void popFront() { ++_member; }

 My current understanding is that the former is incorrect, but 
 I'm looking for confirmation of that. I can't find it written 
 down anywhere.
Here is how it is implemented in the book of Andrew: property bool empty(T)(T[] a) { return a.length == 0; } property ref T front(T)(T[] a) { return a[0]; } void popFront(T)(ref T[] a) { a = a[1 .. $]; }
Jun 07 2015
parent "Dennis Ritchie" <dennis.ritchie mail.ru> writes:
On Monday, 8 June 2015 at 01:29:19 UTC, Dennis Ritchie wrote:
 Here is how it is implemented in the book of Andrew:
Sorry, *Andrei.
Jun 07 2015
prev sibling parent reply Jonathan M Davis via Digitalmars-d-learn writes:
On Monday, June 08, 2015 00:42:07 Mike Parker via Digitalmars-d-learn wrote:
 When implementing a custom range, is it correct to say that
 consecutive calls to r.front with no intervening calls to
 popFront should return the same value? Seems like I read
 something along those lines before, but I can't find it anywhere.
Yes. I was actually talking with Walter about this at dconf. Two consecutive calls to front must return equivalent values (but not necessarily exactly the same object - e.g. map!((a) => to!string(a))(range) is going to return equal strings, but they won't be the exact same string). It would be a fundamental violation of the range concept for multiple calls to front to return values that were not equal if popFront were not called in between. Also, a range cannot depend on empty or front being called in order to iterate correctly. It _can_ choose to do work in those functions instead of just popFront (e.g. map does), but it has to work to just have popFront called without calling empty or front (e.g. if you know that the range has more than 10 elements, you should be free to call popFront 10 times without checking empty or accessing front). - Jonathan M Davis
Jun 07 2015
parent reply Mike Parker <aldacron gmail.com> writes:
On 6/8/2015 12:43 PM, Jonathan M Davis via Digitalmars-d-learn wrote:
 On Monday, June 08, 2015 00:42:07 Mike Parker via Digitalmars-d-learn wrote:
 When implementing a custom range, is it correct to say that
 consecutive calls to r.front with no intervening calls to
 popFront should return the same value? Seems like I read
 something along those lines before, but I can't find it anywhere.
Yes. I was actually talking with Walter about this at dconf. Two consecutive calls to front must return equivalent values (but not necessarily exactly the same object - e.g. map!((a) => to!string(a))(range) is going to return equal strings, but they won't be the exact same string). It would be a fundamental violation of the range concept for multiple calls to front to return values that were not equal if popFront were not called in between. Also, a range cannot depend on empty or front being called in order to iterate correctly. It _can_ choose to do work in those functions instead of just popFront (e.g. map does), but it has to work to just have popFront called without calling empty or front (e.g. if you know that the range has more than 10 elements, you should be free to call popFront 10 times without checking empty or accessing front). - Jonathan M Davis
Thanks, Jonathan. That's what I was looking for.
Jun 07 2015
parent Jonathan M Davis via Digitalmars-d-learn writes:
On Monday, June 08, 2015 13:51:18 Mike Parker via Digitalmars-d-learn wrote:
 On 6/8/2015 12:43 PM, Jonathan M Davis via Digitalmars-d-learn wrote:
 On Monday, June 08, 2015 00:42:07 Mike Parker via Digitalmars-d-learn wrote:
 When implementing a custom range, is it correct to say that
 consecutive calls to r.front with no intervening calls to
 popFront should return the same value? Seems like I read
 something along those lines before, but I can't find it anywhere.
Yes. I was actually talking with Walter about this at dconf. Two consecutive calls to front must return equivalent values (but not necessarily exactly the same object - e.g. map!((a) => to!string(a))(range) is going to return equal strings, but they won't be the exact same string). It would be a fundamental violation of the range concept for multiple calls to front to return values that were not equal if popFront were not called in between. Also, a range cannot depend on empty or front being called in order to iterate correctly. It _can_ choose to do work in those functions instead of just popFront (e.g. map does), but it has to work to just have popFront called without calling empty or front (e.g. if you know that the range has more than 10 elements, you should be free to call popFront 10 times without checking empty or accessing front). - Jonathan M Davis
Thanks, Jonathan. That's what I was looking for.
Though I should probably note that calling front or popFront when empty is true is undefined behavior. We've taken to doing stuff like version(assert) if(empty) throw new RangeError; in Phobos in front and popFront, but you can't rely on any particular behavior if you call front or popFront on an empty range. So, you can skip calls to empty if you _know_ that the range isn't empty, but if you don't know, then you're risking undefined behavior if you call front or popFront without checking empty. - Jonathan M Davis
Jun 07 2015