> 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

Reply via email to