<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=""><br class=""><div><blockquote type="cite" class=""><div class="">On Jun 10, 2016, at 12:59 PM, Xiaodi Wu via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class=""><div class="gmail_extra"><div class="gmail_quote">On Fri, Jun 10, 2016 at 12:30 PM, let var go <span dir="ltr" class="">&lt;<a href="mailto:letvargo@gmail.com" target="_blank" class="">letvargo@gmail.com</a>&gt;</span> wrote:<br class=""><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr" class=""><div class="">I respect that anti-goal, but I think being over-rigid about limiting developers' choice of expression is also an anti-goal.</div><div class=""><br class=""></div><div class="">To me, it is like guard statements vs. if-let statements. Some people find one to be more clear than the other. Often times the best choice depends on the context. Sometimes a guard statement can be re-written as an if-let statement in a way that makes the code more clear, and vice versa.</div></div></blockquote><div class=""><br class=""></div><div class="">The comparison with `guard` and `if` is a little inapt. The introduction of `guard` solved a practical daily issue with `if` that was nicknamed the pyramid of doom, where successive `if let` statements caused code to be severely nested in braces and nearly unreadable. Further, you must exist the scope with `guard`; thus, its use signals an intention not possible with `if`. If, on the other hand, you do not wish to exit the scope, you must use `if`. So in a Venn diagram, there are independent uses for `if` that cannot be fulfilled by `guard`, and uses for `guard` that would be unreadable if rewritten with `if`.</div><div class="">&nbsp;</div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr" class=""><div class="">And different people will inevitably have different personal preferences - their own "style", if you will - and will favor one over the other. But it would be a mistake to force everyone into one box in order to prevent the fracturing of the Swift community into "dialects."</div></div></blockquote><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr" class=""><div class=""><br class=""></div><div class="">But most importantly (and this is really the kicker for me) there are times when the "where" syntax provides the maximum amount of clarity in the context of my code, and I don't want to lose that expressive power.<br class=""></div></div></blockquote><div class=""><br class=""></div><div class="">This is the key and salient point here. Would you be able to share some examples where the `where` syntax provides a clear win in clarity? That would definitely be a huge pro, if it can be used to solve issues in expressiveness much like `guard` allowed elimination of the pyramid of doom.</div></div></div></div></div></blockquote><div><br class=""></div><div>I’d hate to lose `where` in for-in loops; I use it a lot. My own 2c on it is that I think if you look at isolated uses of `where` it’s not adding much clarity, but having it can allow you to adopt more-consistent patterns overall…which IMHO *does* result in clearer code.</div><div><br class=""></div><div>I’ll provide two examples of such “consistent patterns” and how the presence of `for`-`in` `where` helps stick with them.</div><div><br class=""></div><div>First Pattern: for some simple types I like to do data-driven unit tests — here’s a collection of values to test, here’s a basic, “algebraic" property that should apply, test it actually does, and so on.</div><div><br class=""></div><div>When I write a set of tests like that, I like to have a single variable holding the “instances to test” that is shared by all relevant tests; this lets me start with only a handful of values, confirm it seems to work, and then have a single place to edit once I’m ready to expand the values we test upon.</div><div><br class=""></div><div>Such tests might wind up looking like this:</div><div><br class=""></div><div>&nbsp; func testNaiveAncestor() {</div><div>&nbsp; &nbsp; &nbsp;// the root has no ancestor so we simply to skip it:</div><div>&nbsp; &nbsp; &nbsp;for position in testPositions where !position.isRootPosition {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; XCTAssertLessThan(</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;position.naiveAncestor(),&nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;position</div><div>&nbsp; &nbsp; &nbsp; &nbsp; )</div><div>&nbsp; &nbsp; &nbsp;}</div><div>&nbsp; }</div><div><br class=""></div><div><div>&nbsp; func testNaiveSuccessor() {</div><div>&nbsp; &nbsp; &nbsp;for position in testPositions {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; XCTAssertGreaterThan(</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;position.naiveSuccessor(),&nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;position</div><div>&nbsp; &nbsp; &nbsp; &nbsp; )</div><div>&nbsp; &nbsp; &nbsp;}</div><div>&nbsp; }</div><div class=""><br class=""></div><div class="">…where `testPositions` holds the values to test, and the two tests are each testing a basic algebraic property. Having `where` available on for-loops makes it possible to write these in such a way that the intended parallelism between the two is visually-apparent—you can tell they’re the same sort of thing just by looking at them—and it does so in a way that makes few assumptions on the type-or-contents of `testPositions`.&nbsp;</div><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 class=""><br class=""></div><div class="">This is as short as I can make it:</div><div class=""><br class=""></div><div class=""><div class="">&nbsp; /// Returns the portion of our frame that *might* be visible on-screen; doesn't</div><div class="">&nbsp; /// handle occlusion, but unlike `approximateWindowRegion` will account for&nbsp;</div><div class="">&nbsp; /// clipping done by our superviews.</div><div class="">&nbsp; ///</div><div class="">&nbsp; /// - note: `intersectionRegion(with view: UIView)` takes `self.bounds`, converts</div><div class="">&nbsp; /// &nbsp; &nbsp; &nbsp; &nbsp; it to `view`'s coordinates, intersects with `view.bounds`, then converts</div><div class="">&nbsp; /// &nbsp; &nbsp; &nbsp; &nbsp; that back to `self`'s coordinates...returning `nil` for any empty rects.</div><div class="">&nbsp; ///</div><div class="">&nbsp; @warn_unused_result</div><div class="">&nbsp; public final func approximateVisibleRegion() -&gt; CGRect? {</div><div class="">&nbsp; &nbsp; // before checking everything, confirm we *have a window* and that our</div><div class="">&nbsp; &nbsp; // position vis-a-vis the window could *possibly* make sense</div><div class="">&nbsp; &nbsp; // no window =&gt; not visible</div><div class="">&nbsp; &nbsp; guard let w = self.window else {</div><div class="">&nbsp; &nbsp; &nbsp; return nil</div><div class="">&nbsp; &nbsp; }</div><div class="">&nbsp; &nbsp; // empty "frame-intersect-window" =&gt; not visible</div><div class="">&nbsp; &nbsp; guard let regionInWindow = self.intersectionRegion(with: w) else {</div><div class="">&nbsp; &nbsp; &nbsp; return nil</div><div class="">&nbsp; &nbsp; }</div><div class="">&nbsp; &nbsp;&nbsp;</div><div class="">&nbsp; &nbsp; // now we prepare to "walk upstream":</div><div class="">&nbsp; &nbsp; var lastVisitedView = self</div><div class="">&nbsp; &nbsp; var currentFrame = regionInWindow</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; // walk "upstream" (starting from our superview), skipping:</div><div class="">&nbsp; &nbsp; // - superviews that don't clip-to-bounds</div><div class="">&nbsp; &nbsp; // - the window (since we already took our intersection with it)</div><div class="">&nbsp; &nbsp; for upstreamView in self.exclusiveSuperviewSequence() where upstreamView.clipsToBounds &amp;&amp; upstreamView !== w {</div><div class="">&nbsp; &nbsp; &nbsp; // finding a nil intersection =&gt; not visible, early-exit</div><div class="">&nbsp; &nbsp; &nbsp; guard let upstreamIntersection = lastVisitedView.intersectionRegion(with: upstreamView) else {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; return nil</div><div class="">&nbsp; &nbsp; &nbsp; }</div><div class="">&nbsp; &nbsp; &nbsp; lastVisitedView = upstreamView</div><div class="">&nbsp; &nbsp; &nbsp; currentFrame = upstreamIntersection</div><div class="">&nbsp; &nbsp; }</div><div class="">&nbsp; &nbsp; // belt-and-suspenders final steps:</div><div class="">&nbsp; &nbsp; assert(!currentFrame.isEmpty &amp;&amp; !currentFrame.isNull)</div><div class="">&nbsp; &nbsp; return self.convertRect(</div><div class="">&nbsp; &nbsp; &nbsp; currentFrame,&nbsp;</div><div class="">&nbsp; &nbsp; &nbsp; fromView: lastVisitedView</div><div class="">&nbsp; &nbsp; ).onlyIfNonEmpty</div><div class="">&nbsp; }</div></div><div class=""><br class=""></div><div class="">…and without `where` on `for`-`in` loops, the main `for` loop winds up looking like one of these:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; // with `if`:</div><div class=""><div class="">&nbsp; &nbsp; for upstreamView in self.exclusiveSuperviewSequence() {</div><div class="">&nbsp; &nbsp; &nbsp; if upstreamView.clipsToBounds &amp;&amp; upstreamView !== w {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; // finding a nil intersection =&gt; not visible, early-exit</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; guard let upstreamIntersection = lastVisitedView.intersectionRegion(with: upstreamView) else {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return nil</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; }</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; lastVisitedView = upstreamView</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; currentFrame = upstreamIntersection</div><div class="">&nbsp; &nbsp; &nbsp; }</div><div class="">&nbsp; &nbsp; }</div></div><div class=""><br class=""></div><div class=""><div class="">&nbsp; &nbsp; // with mixed-guard usage:</div><div class=""><div class="">&nbsp; &nbsp; for upstreamView in self.exclusiveSuperviewSequence() {</div><div class="">&nbsp; &nbsp; &nbsp; guard upstreamView.clipsToBounds &amp;&amp; upstreamView !== w else {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; continue</div><div class="">&nbsp; &nbsp; &nbsp; }</div><div class="">&nbsp; &nbsp; &nbsp; // finding a nil intersection =&gt; not visible, early-exit</div><div class="">&nbsp; &nbsp; &nbsp; guard let upstreamIntersection = lastVisitedView.intersectionRegion(with: upstreamView) else {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; return nil</div><div class="">&nbsp; &nbsp; &nbsp; }</div><div class="">&nbsp; &nbsp; &nbsp; lastVisitedView = upstreamView</div><div class="">&nbsp; &nbsp; &nbsp; currentFrame = upstreamIntersection</div><div class="">&nbsp; &nbsp; &nbsp; }</div><div class="">&nbsp; &nbsp; }</div></div></div><div class=""><br class=""></div><div class="">…and again neither one is *awful*, but:</div><div class=""><br class=""></div><div class="">- the one with `if` adds another level of nesting (annoying!)</div><div class="">- the one with “guard” has mixed “guard” usage (continue/exit)</div><div class=""><br class=""></div><div class="">…and since I like to stick to early-exit guard—it makes it easier to read if “guard == exit method”—I’d have to go with the nesting option, which I just don’t like much.</div><div class=""><br class=""></div><div class="">Those are the strongest examples I can find; the rest are all essentially like this:</div><div class=""><br class=""></div><div class="">&nbsp; extension Dictionary {</div></div><div><br class=""></div><div>&nbsp; &nbsp; // with `where`</div><div>&nbsp; &nbsp; func mapValues&lt;T&gt;(excludingKeys keySet: Set&lt;Key&gt;, @noescape valueMap: (Value) -&gt; T) -&gt; [Key:T] {</div><div>&nbsp; &nbsp; &nbsp; guard !keySet.isEmpty else {&nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; return self.mapValues(valueMap)&nbsp;</div><div>&nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; var result: [Key:T] = [:]</div><div>&nbsp; &nbsp; &nbsp; for (key,value) in self where !keySet.contains(key) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; result[key] = valueMap(result)</div><div>&nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; return result</div><div>&nbsp; &nbsp; }</div><div><br class=""></div><div>&nbsp; &nbsp; // without `where`, `if`:</div><div><div>&nbsp; &nbsp; func mapValues&lt;T&gt;(excludingKeys keySet: Set&lt;Key&gt;, @noescape valueMap: (Value) -&gt; T) -&gt; [Key:T] {</div><div>&nbsp; &nbsp; &nbsp; guard !keySet.isEmpty else {&nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; return self.mapValues(valueMap)&nbsp;</div><div>&nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; var result: [Key:T] = [:]</div><div>&nbsp; &nbsp; &nbsp; for (key,value) in self {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; if !keySet.contains(key) {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; result[key] = valueMap(result)</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; return result</div><div>&nbsp; &nbsp; }</div><div class=""><br class=""></div><div class=""><div>&nbsp; &nbsp; // without `where`, `guard`:</div><div><div>&nbsp; &nbsp; func mapValues&lt;T&gt;(excludingKeys keySet: Set&lt;Key&gt;, @noescape valueMap: (Value) -&gt; T) -&gt; [Key:T] {</div><div>&nbsp; &nbsp; &nbsp; guard !keySet.isEmpty else {&nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; return self.mapValues(valueMap)&nbsp;</div><div>&nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; var result: [Key:T] = [:]</div><div>&nbsp; &nbsp; &nbsp; for (key,value) in self {</div><div>&nbsp; &nbsp; &nbsp; &nbsp; guard keySet.contains(key) else {&nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; continue&nbsp;</div><div>&nbsp; &nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; &nbsp; result[key] = valueMap(result)</div><div>&nbsp; &nbsp; &nbsp; }</div><div>&nbsp; &nbsp; &nbsp; return result</div><div>&nbsp; &nbsp; }</div><div class=""><br class=""></div></div></div></div><div>&nbsp; }</div><div><br class=""></div><div>…where again I don’t like “continue” `guard` and thus would wind up picking the `if` variant, which adds another level of nesting (or use `.lazy.filter` and trust the compiler’s going to boil away the overhead for me).</div><div><br class=""></div><div>So in conclusion, IMHO `where` on a `for`-`in` is a *modest* improvement in clarity when considered in isolation, but is handier than it may initially seem b/c it can allow for broader overall consistency of style.</div><div><br class=""></div><div>I thus would be in favor of keeping `where` on for-in, or if it must be removed doing so with the intent to restore some better-designed equivalent shortly after removal.</div><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class="gmail_extra"><div class="gmail_quote"><div class="">&nbsp;</div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr" class=""><div class=""></div><div class=""><div class="h5"><br class=""><div class="gmail_quote"><div dir="ltr" class="">On Fri, Jun 10, 2016 at 10:17 AM Xiaodi Wu &lt;<a href="mailto:xiaodi.wu@gmail.com" target="_blank" class="">xiaodi.wu@gmail.com</a>&gt; wrote:<br class=""></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="white-space:pre-wrap" class="">I think this idea--if you don't like it, then you don't have to use it--is indicative of a key worry here: it's inessential to the language and promotes dialects wherein certain people use it and others wherein they don't. This is an anti-goal.<br class=""></div><br class=""><div class="gmail_quote"><div dir="ltr" class="">On Fri, Jun 10, 2016 at 12:10 let var go &lt;<a href="mailto:letvargo@gmail.com" target="_blank" class="">letvargo@gmail.com</a>&gt; wrote:<br class=""></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr" class="">Leave it in!<div class=""><br class=""><div class="">It's a great little tool. I don't use it very often, but when I do it is because I've decided that in the context of that piece of code it does exactly what I want it to do with the maximum amount of clarity.</div><div class=""><br class=""></div></div><div class="">If you don't like it, then don't use it, but I can't see how it detracts from the language at all.</div><div class=""><br class=""></div><div class="">The *only* argument that I have heard for removing it is that some people don't immediately intuit how to use it. I didn't have any trouble with it at all. It follows one of the most basic programming patterns ever: "For all x in X, if predicate P is true, do something." The use of the keyword "where" makes perfect sense in that context, and when I read it out loud, it sounds natural: "For all x in X where P, do something." That is an elegant, succinct, and clear way of stating exactly what I want my program to do.</div><div class=""><br class=""></div><div class="">I don't doubt that it has caused some confusion for some people, but I'm not sold that that is a good enough reason to get rid of it. It seems strange to get rid of a tool because not everyone understands how to use it immediately, without ever having to ask a single question. As long as its not a dangerous tool (and it isn't), then keep it in the workshop for those times when it comes in handy. And even if there is some initial confusion, it doesn't sound like it lasted that long. It's more like, "Does this work like X, or does this work like Y? Let's see...oh, it works like X. Ok." That's the entire learning curve...about 5 seconds of curiosity followed by the blissful feeling of resolution.</div></div><br class=""><div class="gmail_quote"><div dir="ltr" class="">On Fri, Jun 10, 2016 at 9:32 AM Xiaodi Wu via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>&gt; wrote:<br class=""></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr" class=""><div class="gmail_extra"><div class="gmail_quote">On Fri, Jun 10, 2016 at 11:23 AM, Sean Heber via swift-evolution <span dir="ltr" class="">&lt;<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>&gt;</span> wrote:<br class=""><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">&gt; And to follow-up to myself once again, I went to my "Cool 3rd Party Swift Repos" folder and did the same search. Among the 15 repos in that folder, a joint search returned about 650 hits on for-in (again with some false positives) and not a single for-in-while use.<br class="">
<br class="">
</span>Weird. My own Swift projects (not on Github :P) use “where” all the time with for loops. I really like it and think it reads *and* writes far better as well as makes for nicer one-liners. In one project, by rough count, I have about 20 that use “where” vs. 40 in that same project not using “where”.<br class="">
<br class="">
In another smaller test project, there are only 10 for loops, but even so one still managed to use where.<br class="">
<br class="">
Not a lot of data without looking at even more projects, I admit, but this seems to suggest that the usage of “where” is going to be very developer-dependent. Perhaps there’s some factor of prior background at work here? (I’ve done a lot of SQL in another life, for example.)<br class=""></blockquote><div class=""><br class=""></div></div></div></div><div dir="ltr" class=""><div class="gmail_extra"><div class="gmail_quote"><div class="">That is worrying if true, because it suggests that it's enabling 'dialects' of Swift, an explicit anti-goal of the language.</div></div></div></div><div dir="ltr" class=""><div class="gmail_extra"><div class="gmail_quote"><div class="">&nbsp;</div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br class="">
I feel like “where” is a more declarative construct and that we should be encouraging that way of thinking in general. When using it, it feels like “magic” for some reason - even though there’s nothing special about it. It feels like I’ve made the language work *for me* a little bit rather than me having to contort my solution to the will of the language. This may be highly subjective.<br class="">
<br class="">
l8r<br class="">
<span class=""><font color="#888888" class="">Sean<br class="">
</font></span><div class=""><div class=""><br class="">
_______________________________________________<br class="">
swift-evolution mailing list<br class="">
<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a><br class="">
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class="">
</div></div></blockquote></div></div></div>
_______________________________________________<br class="">
swift-evolution mailing list<br class="">
<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a><br class="">
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class="">
</blockquote></div>
</blockquote></div>
</blockquote></div></div></div></div>
</blockquote></div><br class=""></div></div>
_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-evolution<br class=""></div></blockquote></div><br class=""></body></html>