[swift-evolution] [DRAFT] Regularizing Where Grammar (was Re: Add a while clause to for loops)

Brent Royal-Gordon brent at architechies.com
Fri Jun 10 13:05:58 CDT 2016

> I am curious, is there any conflict with the reasoning to move where here compared to the accepted SE-0081 "Move where clause to end of declaration" https://lists.swift.org/pipermail/swift-evolution-announce/2016-May/000161.html
> We moved the where clause to before the body in one case (SE-0081) and now we are trying to move the where clause from before the body to right next to the variable. 
> In SE-0081: "With the proposed change, where clauses do not impede the main declaration and are also more easily formattable"
> I know these are different uses but it is beginning to hurt my head where all the where clauses are suppose to go in different contexts

I understand why this would confuse you, but there are practical reasons for them to be different.

The `where` clause is used in a couple different ways:

* In a declaration, it specifies additional type information—for instance, that an associated type conforms to a certain protocol or matches another associated type on a different type parameter.

	func append<C: Collection>(contentsOf other: C) where C.Iterator.Element == Self.Iterator.Element { … }

* In a `case` statement or other pattern, it specifies a Boolean condition which must be met for the pattern to match.

	switch value {
	case .result(let character) where emoji.contains(character):
		print("Hello, millennial!")
	case .result(_):
		print("Hello, fogey!")
		print("Goodbye, world!")

Both versions of the clause refine a match to specify additional conditions; that's why they use the same keyword. But they're actually quite different.

In particular, one big difference between the two is that you can only attach one `where` clause to a declaration, but there might be many `where` clauses in a pattern match. For instance, in this example:

	enum X { case a, b }
	switch X.a {
	case .a, .b where 1 == 0:

The `where` clause only applies to the `.b`, not the `.a`, so the code will print "Matched". To make it print "Didn't", you'd have to write `case .a where 1 == 0, .b where 1 == 0`. In other words, the `where` clause is part of the specific pattern, not the `case` statement as a whole, and so it *must* be attached to the specific pattern.

The `for` syntax, however, does not respect this rule. It inserts the `in` clause between the pattern (the thing after the `for` keyword is a pattern too, even if it doesn't have a `case` keyword) and its `where` clause. That's not consistent with `switch`-`case`'s syntax, and in practice, I find it leads to confusion about what `where` does.

For a declaration, however, there can only be one `where` clause, and you can equally well view it as applying to only the generic parameter list (the old way) or to the entire declaration (the new way). There are several reasons why it's very convenient to put it at the end:

1. Declaration `where` clauses tend to involve lots of verbose names and be very long.
2. Declaration `where` clauses sometimes need to be attached to declarations with no generic parameter list, like `extension` and hopefully soon `associatedtype`.
3. Declaration `where` clauses embedded in a generic parameter list end up wedging a bunch of usually unimportant information between two of the most important parts of the declaration: the list of generic parameters and the list of regular parameters. This ends up turning the whole thing into a jumbled mess.

So even though both kinds of `where` clause do broadly similar things, they face very different constraints and pressures, and thus are positioned a little bit differently. That's unfortunate, but probably unavoidable.

The proposal being discussed in this thread is actually trying to improve this situation by making pattern `where` clauses in `for` loops match pattern `where` clauses in `switch` statements. In other words, I believe it actually improves consistency over the status quo. So if you're confused about where you put `where`, this should make it a little easier to keep things straight.

Brent Royal-Gordon

More information about the swift-evolution mailing list