Comment #0 by snarwin+bugzilla — 2019-01-15T21:59:11Z
Example:
---
int count = 0;
int counter()
{
return count++;
}
void main()
{
import std.algorithm;
import std.range;
import std.stdio;
auto gen = generate!counter;
gen.take(3).each!writeln;
assert(count == 3); // fails, count == 4
}
---
This behavior leads to two related problems:
1) Ranges, in general, are expected to be lazy. Eagerly calling the generator function on construction and in popFront violates that expectation.
2) As a result, writing optimal code using ranges created with `generate` (that is, code which does no unnecessary work) requires special-case handling, since Phobos' algorithms (for example, `take`, above) "naively" assume that construction and popFront are cheap.
These problems are especially bothersome when the generator function is expensive to call (for example, if it accesses the network).
Comment #1 by dkorpel — 2021-05-06T22:53:27Z
Just got hit by this today, my `generate!(() => readln()).take(10).array` discarded the line after the 10 lines put into the array.
This is really annoying, but changing this would be a breaking change, so I'm afraid the fix would be either:
- a template parameter 'caching' with default value of `true`
- a new synonym symbol, similar to `approxEqual => isClose`, with the possibility to deprecate the old symbol (caching can still be achieved by doing `generate!(f).cache`). I'm not sure what that synonym would be, things that come to mind are `generateLazy`, `successiveCalls`, `repeatEvaluate`, but I'm not a big fan of them.
Comment #2 by remi.thebault — 2022-05-06T16:50:40Z
*** Issue 23094 has been marked as a duplicate of this issue. ***
Comment #3 by dlang-bot — 2022-05-06T17:37:06Z
@rtbo created dlang/phobos pull request #8453 "fix issue 19587" fixing this issue:
- fix issue 19587
avoid that std.range.generate calls
fun one time too many
https://github.com/dlang/phobos/pull/8453
Comment #4 by robert.schadek — 2024-12-01T16:34:47Z