[Issue 16326] New: filter is not lazy enough & has weird save behavior
via Digitalmars-d-bugs
digitalmars-d-bugs at puremagic.com
Wed Jul 27 07:15:37 PDT 2016
https://issues.dlang.org/show_bug.cgi?id=16326
Issue ID: 16326
Summary: filter is not lazy enough & has weird save behavior
Product: D
Version: D2
Hardware: All
URL: http://dlang.org/
OS: All
Status: NEW
Severity: normal
Priority: P3
Component: phobos
Assignee: nobody at puremagic.com
Reporter: eyal at weka.io
std.algorithm.filter's this() constructor advances the underlying range until
the predicate is fulfilled. This happens *BEFORE* its next item is demanded
(i.e: Not lazily).
This has a number of unfortunate consequences:
Firstly, it makes 'save' which uses the constructor to copy the range sensitive
to mutations in the underlying range:
void sensitiveToMutations() {
{
auto f = [1,2,3].filter!(x => x%2==0);
auto g = f.save;
f.front = 5;
assert(g.front == 5); // works
}
{
auto f = [1,2,3].filter!(x => x%2==0);
f.front = 5;
auto g = f.save;
assert(g.front == 5); // fails!
}
}
The above is reduced from actual confusing behavior we've experienced.
This extra eagerness can easily cause infinite loops:
void loopsForever() {
import std.range : repeat;
// This loops forever:
auto f = repeat(1).filter!(x=>x%2 == 0);
}
And lastly, if the predicate is expensive or has undesirable side effects that
we wish to keep to a minimum, filter is wasteful:
void redundantPredicateCalls() {
import std.stdio : writeln;
auto veryExpensivePredicate(int x) { writeln("OUCH"); return true; }
// OUCH number 1 (already redundant)
auto f = [1,2,3].filter!veryExpensivePredicate;
// OUCH number 2 (Redundant!)
auto g = f.save;
}
--
More information about the Digitalmars-d-bugs
mailing list