> On Jun 9, 2016, at 5:51 AM, Erica Sadun via swift-evolution
> <[email protected]> wrote:
>
>
>> On Jun 8, 2016, at 9:36 PM, Brent Royal-Gordon <[email protected]
>> <mailto:[email protected]>> 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
> [email protected]
> https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution