On Friday, 8 April 2016 at 03:20:53 UTC, Puming wrote:
On Friday, 8 April 2016 at 02:49:01 UTC, Jonathan M Davis wrote:
[...]

Thanks. I'll adopt this idiom. Hopefully it gets used often enough to warrent a phobos function :-)

What would such a function look like? I don't think such a thing could exist. This is more than just an idiom, IMO. It's a basic principle of ranges that, if not followed, is likely to produce a broken range and/or one whose front is more expensive than it needs to be. The trouble is that it isn't necessarily obvious and is easy to overlook when first implementing a custom range.

In Learning D, I used a custom FilteredRange to introduce the concept of ranges. It has a member function called skipNext which does the work of the filtering. It's called once in the constructor to 'prime' the range with the first value that matches the filter, then inside every call to popFront to find the next match. I closed that section with this paragraph:

"It might be tempting to take the filtering logic out of the skipNext method and add it to front, which is another way to guarantee that it's performed on every element. Then no work would need to be done in the constructor and popFront would simply become a wrapper for _source.popFront. The problem with that approach is that front can potentially be called multiple times without calling popFront in between, meaning the predicate will be tested on each call. That's unnecessary work. As a general rule, any work that needs to be done inside a range to prepare a front element should happen as a result of calling popFront, leaving front to simply
focus on returning the current element."

A lazy range should be advanced in the constructor when it needs to be (usually when there is some criterion for an element to be returned from front) and always in popFront, but never in front.

Reply via email to