[swift-evolution] [Review] SE-0105: Removing Where Clauses from For-In Loops

Brent Royal-Gordon brent at architechies.com
Fri Jun 24 22:25:26 CDT 2016

> As detailed in the proposal, the keywords cover the space of continue false, continue true,  break true, break false.

But the goal of covering all four of these options is arbitrary and inconsistent with the rest of the language. Moreover, it's arbitrary and inconsistent in a way that inflates the apparent magnitude of the problem.

Firstly: There is no need whatsoever for both "true" and "false" versions of each condition. Swift doesn't have `if` and `unless`, or `guard` and `prevent`, or `while` and `until`. It expects you to use the not operator or reverse the sense of your comparisons (`!=` instead of `==`, `>=` instead of `<`, etc.). We can do the same thing here. If `if !` is good enough, then so is `where !`.

Secondly: Yes, `where` and `while` are both available as list operations (`filter` and `prefix(while:)`), but so are `map` and `sorted`, and nobody is suggesting we need those as keywords. (Well, some people have suggested some additional `for` keywords, but they're wrong.) If we feel that `where` is special, there's nothing wrong with offering only `where`.

And I *would* argue that `where` is special. It's special because skipping an element feels less like control flow than terminating a loop. It's special because `where` is not order-dependent, but `while` is. It's special because terminating the loop is a more drastic action. It's special because the `continue` keyword is less clear than the `break` keyword, but is considered an inviolable term of art. It's special because I suspect (but admittedly cannot prove) that `continue` is more frequently used at the top of a loop, controlled by a single conditional statement based on a side-effect-free boolean operation, than `break`.

Think of it this way: We have not accepted the often-proposed `else`-less `guard`, but if we did, there is broad agreement that, absent an "always `return`" rule for simplicity, the most obvious body to infer inside a loop is `continue`. There are reasons for that, and they're the exact same reasons we support `where` but not `while`.

* * *

My review of this proposal follows.

> 	* What is your evaluation of the proposal?

I think the motivation is weak and do not find it compelling.

The "elevates one style above other related styles" motivation fails to convince me for the reasons described above; "difficult to document separately at its point of use" can be addressed simply by adding a newline before the `where` clause; "hard to breakpoint and debug" is true of any expression, and is easily addressed by extracting that expression into an inner function; and "rarely used" is, in my opinion, more a result of how it is taught and documented than of how useful it is.

In my opinion, the *only* valid argument cited for the removal of `where` is that learners sometimes misunderstand it. I'm very sympathetic to learners, and I would like to improve their experience with this feature. But there are many other ways to help them, like:

* Making sure that "The Swift Programming Language" teaches the use of `for`/`where`.

* Adding help content for language keywords to Xcode and Swift Playgrounds.

* Making syntax adjustments that might improve clarity, like my suggestion that putting the `where` clause next to the variable might clarify that you are filtering the values which will be seen inside the loop.

* Changing the keyword, if a better keyword can be found.

But at this point, measures like these have not been tried, and I have not heard convincing arguments that they will not work.

Meanwhile, the proposal does not address the problems it causes, suggest that they *should* be addressed in a future proposal, or even acknowledge that there *are* any problems. If `where` is removed, none of its alternatives are nearly as good:

* `guard`/`else`/`continue` clutters the logic with completely avoidable boilerplate.

More worryingly, it obscures the intent: "Skip elements like this" becomes "Elements must be like this, and if they're not, go to the next element". Converting a meaning into mechanical instructions to achieve it is not an improvement. If we wanted to do that, we could dispose of `for`/`in` entirely and replace it with:

	var iterator = collection.makeIterator()
	while let elem = iterator.next() { … }

Folks who wrote AppKit code on Tiger would feel right at home.

* `filter(suchThat:)` (or whatever we call it) is dramatically less efficient and has syntactic issues with that particular slot because trailing closures are unavailable.

* `lazy.filter(suchThat:)` lies on a narrow golden path (it's all too easy to forget the `lazy`) and still has the same syntactic issues as a plain `filter`.

We retired `where` clauses from `if` statements because they were a grammatical hack, an unnatural usage forced on us by the desire to support a feature (multiple optional bindings or pattern matches per keyword) that, in hindsight, we realized was less important. There is no similar consideration driving this proposal. Instead, the justification offered is essentially a series of style complaints and an argument that, if you don't try to teach the feature and you don't try to improve it, some people sometimes guess its meaning incorrectly. That's just not enough.

For the reasons above, I urge the core team to reject this proposal.

> 	* Is the problem being addressed significant enough to warrant a change to Swift?

Quite possibly. But removing `for`/`in`/`where` is an overreaction. When your arm is broken, you put a cast on it; you don't cut it off.

> 	* Does this proposal fit well with the feel and direction of Swift?

Yes in that it's a clean-up attempt, but no in that it forces additional boilerplate.

> 	* If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

`for`/`in`/`where` is necessitated by circumstances that are somewhat unique to Swift among the languages I've used, so I don't really have a basis for comparison.

> 	* How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

Participated pretty heavily in previous discussions.

Brent Royal-Gordon

More information about the swift-evolution mailing list