digitalmars.D.bugs - [Issue 16326] New: filter is not lazy enough & has weird save behavior
- via Digitalmars-d-bugs (52/52) Jul 27 2016 https://issues.dlang.org/show_bug.cgi?id=16326
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 puremagic.com Reporter: eyal 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; } --
Jul 27 2016