> Unlike in switch statements and do loops, a for-in loop's where-clause is 
> separated from the pattern it modifies.

(I think "do loops" is supposed to be "do-catch statements"?)

> for case? pattern in expression where-clause? code-block
> 
> case-item-list → pattern where-clause? | pattern where-clause? , 
> case-item-list
> 
> catch pattern? where-clause? code-block
> 
> This separation makes the clause harder to associate with the pattern, can 
> confuse users as to whether it modifies the expression or the pattern, and 
> represents an inconsistency in Swift's grammar. This proposal regularizes the 
> grammar to match other uses.

I'm definitely in favor of this. (I should be—I'm listed as coauthor.)

While I've never struggled with the `where` clause—I always assumed it was a 
filter—it never read right to me. This way does. When I say it out loud, "for x 
where x less than 10 in numbers" simply seems *far* easier to understand than 
"for x in numbers where x less than 10". There's something about the way the 
"where" combines with "for" that clarifies the entire statement.

I also think this better matches the grammar of the `case` statements in a 
`switch`. Erica quotes the formal grammar above, but you can actually see this 
in running code: in a `switch` statement, a compound case with a `where` clause 
like:

        case .foo, .bar where baz():

Only applies the `where` clause to the last pattern (.bar, but not .foo). 
That's because the rule is that the `where` belongs to the *pattern*, not the 
entire statement.

As a question of the proposal's drafting—as opposed to the feature being 
proposed—I do think that we should include an example of code before and after 
the change. The isOdd example ought to do.

> Note where clauses in case conditions and optional bindings have been removed 
> in SE-0099.

I think there's actually a case to be made (no pun intended) for bringing 
`where` back in case conditions, but with an analogous movement of the clause's 
position. In other words, where (post-SE-0099) we have this production:

        case-condition → "case" pattern initializer

We would change it to:

        case-condition → "case" pattern where-clause? initializer

In use, this would look like:

        if case .some(let Point.cartesian(x, y)) where x < y = 
json["rect"]?["origin"].flatMap(.init(rawValue:)) { … }

Of course, the above could equally be written without a `where` clause:

        if case .some(let Point.cartesian(x, y)) = 
json["rect"]?["origin"].flatMap(.init(rawValue:)), x < y { … }

But nevertheless, I think it's a good idea. Why? Two reasons:

1. Consistency. If this proposal is accepted, all other `case` statements will 
be able to take a `where` clause in the exact same position.

2. Expressiveness. In its new position, the `where` clause is actually in the 
middle—not at the end—of the case condition. This makes its role much more 
clear: `where` in a case condition is for refining the pattern to reject things 
which can't quite be expressed purely as a pattern. With `where` in this 
position, you will not be tempted to use it for a truly unrelated condition, as 
you might if `where` were after the initializer.

You might be able to make an analogous argument for optional bindings, turning 
this:

        optional-binding-head → "let" pattern initializer

Into this:

        optional-binding-head → "let" pattern where-clause? initializer

With results like:

        if let x where x > 5 = optionalX { … }

I'm less convinced this is a good idea; there's no optional binding anywhere 
else in the language to be consistent with, the uses of a `where` clause are 
limited since an optional binding only captures one value anyway, and I don't 
think it makes much sense to complicate such a simple syntax.

-- 
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to