Can't recreate a range?

Paul Backus snarwin at gmail.com
Thu Apr 30 22:39:36 UTC 2020


On Thursday, 30 April 2020 at 18:30:14 UTC, H. S. Teoh wrote:
> On Thu, Apr 30, 2020 at 06:05:55PM +0000, Paul Backus via 
> Digitalmars-d-learn wrote: [...]
>> Doing work in popFront instead of front is usually an 
>> anti-pattern, since it forces eager evaluation of the next 
>> element even when that element is never used. You should only 
>> do this if there's no reasonable way to avoid it.
>
> Really?? IME, usually you *need* to do work in popFront instead 
> of front, because otherwise .empty wouldn't be able to tell 
> whether there is another element or not.  E.g., in filtering a 
> range based on some criterion on each element, you can't defer 
> computing the next element until .front because you can't 
> predict whether there will be another element that won't be 
> dropped by popFront.

There are certainly cases where it can't be avoided. Filter is 
one; file I/O (as Steven Schveighoffer pointed out) is another 
one. Obviously, you gotta do what you gotta do. Still, I think 
that as long as work *can* be deferred to .front, it should be. 
That's the essence of lazy evaluation: only do your computation 
once you're absolutely sure it's necessary.

> Also, for ranges based on generator functions, if .front is 
> lazy then you need to keep extra baggage around your range to 
> indicate whether or not the generator has been invoked yet; 
> it's easier to just always compute the next element eagerly and 
> cache it, and .front just returns the cached data.

std.range.generate is actually a perfect example of the problem 
with doing work in popFront. Because it has to call popFront both 
on construction *and* after every element, consuming n elements 
will call the generator function n+1 times. The final call is 
completely wasted.


More information about the Digitalmars-d-learn mailing list