On Wednesday, 23 November 2016 at 21:19:51 UTC, Jonathan M Davis
wrote:
It's quite feasible if you don't calculate front until it's
called or popFront is called, and then you cache the result so
that subsequent calls to front prior to the call to popFront
return the same result, but it creates additional overhead,
because then every call to front and popFront has to check
whether the value has been calculated yet. And if every range
in the chain of ranges has to do that, then that additional
overhead is going to add up.
Yes, indeed. I actually came up with a general purpose solution
for that a while back via template mixin (although the version in
the post linked to is not the final version: I updated it to use
HaraldZealot's suggestion of making the frontImplementation and
popFrontImplementation the template parameters):
https://forum.dlang.org/post/mailman.263.1439926667.13986.digitalmar...@puremagic.com
In general, it's just cleaner to either calculate front on
every call to front (which doesn't make sense in the case of
random number generators) or to calculate the first front upon
construction and be done with it.
In some ways I think it's cleaner to not privilege the first
front value and go for "true" laziness for all front values --
particularly when dealing with stuff like RandomSample.
The downside is that `.front` becomes non-const. Sometimes I
wonder whether it wouldn't have been better to require that
`popFront()` be called before even the first call to `.front`,
and place the onus on `popFront()` to handle any special-casing
of the first `.front` value.
And I think that the general consensus has been that
calculating front in the constructor and popFront and caching
works better than calculating it on every call to front, but
that doesn't always work (e.g. map), and that caching does
cause issues occasionally.
The case I always think of is: what if your input range is
designed to correspond to sensor observations made at a
particular time? This is a case where cacheing the first value
on construction is very problematic.
For RNGs it's really not such a big deal so long as successive
variates are independent, but for random algorithms I think the
laziness matters, since their popFront is essentially
IO-dependent (in the Haskell-style sense that randomness is IO).