> On Jun 9, 2016, at 5:51 AM, Erica Sadun via swift-evolution > <swift-evolution@swift.org> wrote: > > >> On Jun 8, 2016, at 9:36 PM, Brent Royal-Gordon <br...@architechies.com >> <mailto:br...@architechies.com>> wrote: >> >>> Upon accepting SE-0099, the core team is removing `where` clauses from >>> condition clauses, writing "the 'where' keyword can be retired from its >>> purpose as a boolean condition introducer." >>> >>> Inspiried by Xiaodi Wu, I now propose removing `where` clauses from `for >>> in` loops, where they are better expressed (and read) as guard conditions. >> >> Do you propose to remove `for case` as well? That can equally be handled by >> a `guard case` in the loop body. >> >> Alternate proposal: Move `where` clauses to be adjacent to the >> pattern—rather than the sequence expression—in a `for` loop, just as they >> are in these other syntaxes. >> >> for n where n.isOdd in 1...1_000 { … } >> >> This makes them more consistent with the syntax in `switch` cases and >> `catch` statements, while also IMHO clarifying the role of the `where` >> clause as a filter on the elements seen by the loop. > > I saw your post on that *after* I finished sending this. Moving `where` next > to the pattern, like you'd find in `catch` and switch `case`, the code would > look like this: > > for i where i % 2 == 0 in sequence { > // do stuff > } > > I agree that's really clever and an improvement but after coming up with all > the points about wrong expectations about termination vs filtering, the > better use of guard, and fetishes about vertical compactness, I think (call > it +0.6) I'm going to stick to my guns on this one - and for `for case` too. > I've been wuxxed. > > * New users might expect the sequence to terminate as soon as i % 2 is 1, > rather than the correct interpretation which is "this is a filtering > operation" > * The code can be expressed less ambiguously as > > for i in sequence.filter({ return i % 2 == 0 }) { > // do stuff > }
It's important to keep in mind that .filter without using .lazy copies the array. So you need to keep using sequence.lazy.filter({ return i %2 == 0 }), unless you're OK with giving up some performance, which a) adds boilerplate, b) not many people will remember to do. I've taken the time to run a test, going through milion numbers (several times) using: for i in arr { if i % 2 == 0 { continue } } for i in arr where i % 2 == 0 { } for i in arr.filter({ $0 % 2 == 0 }) { } for i in arr.lazy.filter({ $0 % 2 == 0 }) { } Results: - plain for loop with if-continue: 27.19 seconds (+1.76%) - with where: 26.72 seconds (+0.00%) - .filter: 44.73 seconds (+67.40%) - .lazy.filter: 31.66 seconds (+18.48%) Yes, 100 milion numbers is an extreme, but it demonstrates that any of the suggested expressions will be slower, mainly if the caller doesn't use .lazy (67% !!!). The only comparable solution is adding additional lines of code into the body of the for loop by adding an if statement. > * The while version can be expressed as > > for i in sequence.prefix(while: { return $0 % 2 == 0 } ) { > // do stuff > } > > * The code can also use `guard` statements as needed with `break` and > `continue` > > (And yes, I should have pointed out filter and prefix as well as guard in my > first email) > > -- E > > _______________________________________________ > swift-evolution mailing list > swift-evolution@swift.org > https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution