>
> First, notice how your comment is related to the `where` clause but is
> actually sitting on top of the loop itself. Second, one of these two tests
> visits every element while the other doesn't, and it took me three reads
> before I could see that because I literally couldn't find the `where` clause
> the first two times I scanned through your code. This is a false
> "parallelism," causing the very thing that *isn't* parallel to disappear from
> the reader's eye. Compare instead this alternative, which also flips the
> boolean assertion:
>
> ```
> func testNaiveAncestor() {
> for position in testPositions {
> // the root has no ancestor
> if position.isRootPosition { continue }
> // (notice how I don't even have to comment that we're skipping root,
> // because the code says it explicitly for me)
>
> XCTAssertLessThan(position.naiveAncestor(), position)
> }
> }
> ```
Fair enough; I added the comment when posting here…the original didn’t have
one, because the where clause also explicitly says we’re skipping that one.
To me the parallelism I care about is the following paraphrase:
for testItem in allRelevantPossibilities { someBasicPropertyHolds(testItem) }
for testItem in allRelevantPossibilities { someOtherPropertyHolds(testItem) }
…and adding the logic to skip the irrelevant option into the definition of
“allRelevantPossibilities” seems to do a better job preserving the structural
similarity I care about than throwing in some ad-hoc looking imperative logic
into the test logic itself (even though functionally both are equivalent).
>
> Now, with my rewriting, the part of your test that is strictly similar to the
> other test looks parallel, and the one part that isn't at all similar (the
> skipping part) stands out explicitly and is now self-documenting code.
>
>
> So `where` here, IMHO, isn’t *clearly* clearer in `testNaiveAncestor()`, but
> it lets `testNaiveAncestor()` and `testNaiveSuccessor()` (etc.) be
> *systemically*-clearer, as it were.
>
> Second Pattern: relatedly, I find code is much clearer when `guard` is
> only-ever used for early exits and early returns.
>
> There’s no requirement to *not* use `guard` and `continue` together, but if
> one is willing to stick to `guard` == “early exit / early return” it makes
> code much easier to read and audit.
>
> In a handful of places I have for loops that would need both `continue`-style
> conditionals and also early-exit conditionals; having `where` means I can
> stick to using `guard` for early-exits, whereas without it I’d have extra
> nesting or mixed “early-exit” guard and “continue” guard.
>
> I don't know what to say here. The fact is that `guard` with `continue` is a
> documented and advertised feature of Swift; it's not simply supported by
> accident. Of course, you're free to choose not to use that feature at all.
> And it is true that, currently, `where` allows you to avoid that feature at
> the top of a `for` loop, but anywhere else inside the loop and you'll have to
> deal with extra nesting if you choose to reject `guard` with `continue`.
The same is true of `where`, no? It’s a part of the language, documented, free
to use or not to use when or if you find it helpful (or not).
In the same way you seem to have with `where` after a for-in — and would prefer
to not have to check for it, etc. — I have a hard time following mixed
break/continue/return usage, and prefer to not have to check the body of each
guard clause’s `else` to figure out the control flow.
I can understand that you find that difficulty baffling; I find your
difficulties `where` baffling, but can accept they are sincere.
> IIUC, one of the motivating reasons for introducing `guard` was to solve the
> pyramid of doom problem. So you're rejecting the intended solution for extra
> nesting, at least in certain circumstances, a choice you're obviously free to
> make in your own code. But when it comes to designing a language for
> everyone, the fact that some users reject the intended solution would be
> grounds for re-examining that solution (i.e. `guard`), but the mantra here
> has always been one solution where possible and not multiple. So this
> certainly cannot be a justification for another feature (i.e. `where`) which
> only incidentally provides a substitute solution in certain situations.
Personally I found this use of `where` completely unremarkable and something I
never thought about until I saw this discussion gaining momentum; I was already
used to similar constructs so it just seemed useful in a familiar and
thoroughly-uninteresting way.
That said, I could get behind excising it if there was serious interest in
eventually building-in something like LINQ or comprehensions (etc.); `where`
after a for-in is at this point a bit of an odd duckling.
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution