[swift-evolution] [Pitch] Retiring `where` from for-in loops

Haravikk swift-evolution at haravikk.me
Fri Jun 10 14:35:50 CDT 2016


> On 10 Jun 2016, at 19:10, Xiaodi Wu via swift-evolution <swift-evolution at swift.org> wrote:
> So "inessential" alone is not a good sole criterion--I agree. But it is one of several prongs here: `where` is not only inessential, I argue that it lacks expressiveness (in that what is enabled by it can be expressed equally or even more cogently with `guard`, a more general and more expressive syntax overall), and it detracts from rather than helps with writing correct code, because we hear attestations that its use has gone awry (and the going awry happens at runtime!). So in essence, I would be content with inessential but expressive solutions, but here I argue that `where` is neither essential nor expressive.

You’ve argued this several times, but I think the code speaks well enough for itself:

	for eachValue in theValues where eachValue.isOdd { … }
	for eachValue in theValues {
		guard eachValue.isOdd else { continue }
	}

Not only is it an extra 15+ characters, it’s an extra line, so there’s a definite saving right away.

The key issue is people misunderstanding that where is equivalent to continue and not break; this may be an issue of consistency, which will go away if “where” is doomed to be removed from conditionals (which I believe includes while loops). Otherwise it seems like it’s based on a mistaken assumption that the for in loop wants to terminate rather than continue, but really its purpose is to visit as many matching elements of a sequence as possible (even with c-style for loops most for loops tend to be finite in a way that you can predict the number of loops before they run if you want to), whereas while loops can be considered designed to fail, at least that’s how I was taught to use them. Of course both can be infinite and there’s overlap in how they’re used, but this is how I think about them, and thus what shapes conditions placed upon them.

Again though, if there’ll only be one loop with a where clause like this then I’m not sure it’s as much of an issue.


The obvious solution to clarity or lack of implied meaning is to either add detail (which narrows the gap on guard continue) or rename the keyword to something. In terms of the clarity I’m actually disappointed that Swift doesn’t use the do keyword for loops, as I find the following very clear:

	for eachValue in theValues where eachValue.isOdd do { … }

Reading the last part in isolation “where eachValue.isOdd do” is clearer that the block is skipped, but that the loop isn’t. This is essentially how I read loop blocks already, but since we have a “do” keyword I wish we could use it like this, as I would on all my loops. In fact, with the do present you could easily shorten “where” to “if”, which may even be slightly clearer still:

	for eachValue in theValues if eachValue.isOdd do { … }

This is part of why I’m uncertain about relocating where, as I kind of feel that it’s actually in the right place already, since the where clause determines whether the block is executed, not whether the loop stops, i.e- the program will still visit every element of the sequence if it can, you’re just choosing which ones to actually do work for. Even clearer still if you consider it with a comma in the middle like so:

	for eachValue in theValues, if eachValue.isOdd do { … }

Not really proposing this is a syntax, though if it were possible to write this way today it’s what I’d do, but the last form above is how I ready a where clause on a for loop. I’ve said that it’s equivalent to a guard because a guard is a nice way to replace it when the condition becomes more complex (or you need to break instead), but actually I’d say it’s more equivalent to:

	for eachValue in theValues { if eachValue.isOdd {
		…
	}}

Except I’d never want to write my code that way if I can avoid it (I frequently write code like this for switch statements inside enums, which is I’m eager to see a replacement to switch self, but that’s another issue entirely).


Also, one thing to add is that I really hate writing extra lines if I don’t have to; obviously I’ll do it when a single line gets too complex and cluttered, but one reason I like where is that I don’t have to waste a line inside the loop on a guard statement, which either keeps the focus on the code, or lets me instead use the line for a comment that clarifies my intent exactly; I’m all for self-documenting code, but a comment stating what my aim is better since any mistake in my code could leave my intent in question otherwise.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160610/fd020103/attachment.html>


More information about the swift-evolution mailing list