<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div><blockquote type="cite" class=""><div class=""><div dir="ltr" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><div class="gmail_extra"><div class="gmail_quote"><div class=""><br class=""></div><div class="">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:</div><div class=""><br class=""></div><div class="">```</div><div class="">func testNaiveAncestor() {</div><div class="">&nbsp; for position in testPositions {</div><div class="">&nbsp; &nbsp; // the root has no ancestor</div><div class="">&nbsp; &nbsp;<span class="Apple-converted-space">&nbsp;</span><span style="background-color: rgb(255, 255, 0);" class="">if position.isRootPosition { continue }</span></div><div class=""><div class="">&nbsp; &nbsp; // (notice how I don't even have to comment that we're skipping root,</div><div class="">&nbsp; &nbsp; // because the code says it explicitly for me)</div></div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; XCTAssertLessThan(position.naiveAncestor(), position)</div><div class="">&nbsp; }</div><div class="">}</div><div class="">```</div></div></div></div></div></blockquote><div><br class=""></div><div>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.&nbsp;</div><div><br class=""></div><div>To me the parallelism I care about is the following paraphrase:</div><div><br class=""></div><div>&nbsp; for testItem in allRelevantPossibilities { someBasicPropertyHolds(testItem) }</div><div>&nbsp; for testItem in allRelevantPossibilities { someOtherPropertyHolds(testItem) }</div><div><br class=""></div><div>…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).</div><div><br class=""></div><blockquote type="cite" class=""><div class=""><div dir="ltr" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><div class="gmail_extra"><div class="gmail_quote"><div class=""><br class=""></div><div class="">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.</div><div class=""><br class=""></div><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; padding-left: 1ex;"><div style="word-wrap: break-word;" class=""><div class=""><div class=""><div class=""><br class=""></div><div class="">So `where` here, IMHO, isn’t *clearly* clearer in `testNaiveAncestor()`, but it lets `testNaiveAncestor()` and `testNaiveSuccessor()` (etc.) be *systemically*-clearer, as it were.</div><div class=""><br class=""></div><div class="">Second Pattern: relatedly, I find code is much clearer when `guard` is only-ever used for early exits and early returns.&nbsp;</div><div class=""><br class=""></div><div class="">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.</div><div class=""><br class=""></div><div class="">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.&nbsp;</div></div></div></div></blockquote><div class=""><br class=""></div><div class="">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`.</div></div></div></div></div></blockquote><div><br class=""></div><div>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).</div><div><br class=""></div><div>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.</div><div><br class=""></div><div>I can understand that you find that difficulty baffling; I find your difficulties `where` baffling, but can accept they are sincere.</div><div><br class=""></div><blockquote type="cite" class=""><div class=""><div dir="ltr" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><div class="gmail_extra"><div class="gmail_quote"><div class="">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.</div></div></div></div></div></blockquote><br class=""></div><div><div class="">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.</div><div class=""><br class=""></div><div class="">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.</div><div class=""><br class=""></div></div></body></html>