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

Xiaodi Wu xiaodi.wu at gmail.com
Fri Jun 10 14:45:00 CDT 2016

On Fri, Jun 10, 2016 at 2:35 PM, Haravikk <swift-evolution at haravikk.me>

> 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.

I'm glad this mental model makes sense to you. I'm not in the business of
regularly teaching coding, but this is the first I've heard of the idea
that "while loops want to break, but for loops want to continue." I don't
think this is a widely shared conception of those loops.

> 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.

I'm sorry, but until this discussion I had never heard of a coding style
that advocates for conservation of vertical space. There's a lot of
argument whether 80 characters is still a relevant line length, but I've
never heard discussion that a single long line is better than multiple
lines as a general principle.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160610/83f558bc/attachment.html>

More information about the swift-evolution mailing list