<div dir="ltr">On Fri, Mar 10, 2017 at 6:29 PM, James Froggatt <span dir="ltr">&lt;<a href="mailto:james.froggatt@me.com" target="_blank">james.froggatt@me.com</a>&gt;</span> wrote:<br><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="auto"><span class="gmail-"><div></div><div><br></div><div>On 11 Mar 2017, at 00:21, James Froggatt &lt;<a href="mailto:james.froggatt@me.com" target="_blank">james.froggatt@me.com</a>&gt; wrote:<br><br></div><blockquote type="cite"><div><div></div><div><br></div><div>On 11 Mar 2017, at 00:05, Xiaodi Wu &lt;<a href="mailto:xiaodi.wu@gmail.com" target="_blank">xiaodi.wu@gmail.com</a>&gt; wrote:<br><br></div><blockquote type="cite"><div><div dir="ltr"><div>Some days ago, Ben Cohen laid out the criteria for helper functions in the Standard Library. Here&#39;s some of his very enlightening text and the six criteria:</div><div><br></div><div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">The operation needs to carry its weight. Even once we have ABI stability, so the size of the std lib becomes less of a concern as it could ship as part of the OS, we still need to keep helper method growth under control. APIs bristling with methods like an over-decorated Xmas tree are bad for usability. As mentioned in the String manifesto, String+Foundation currently has over 200 methods/properties. Helpers are no good if you can’t find them to use them.<br></blockquote><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">1. Is it truly a frequent operation?<br>2. Is the helper more readable? Is the composed equivalent obvious at a glance?<br>3. Does the helper have the flexibility to cover all common cases?<br>4. Is there a correctness trap with the composed equivalent? Is there a correctness trap with the helper?<br>5. Is there a performance trap with the composed equivalent? Or with the helper?<br>6. Does the helper actually encourage misuse?</blockquote></div><div><br></div><div>The reasons I&#39;m opposed to adding `clamp` are as follows:</div><div><br></div><div>It is trivially composed from `min` and `max`, with no correctness traps.</div><div><br></div><div>As the discussion above shows, there are correctness traps when you have a `clamp` operation that takes open ranges, whereas the composed form using `min` and `max` does not suffer from the same issue.</div><div><br></div><div>It encourages misuse, because Dave&#39;s desired use case (for indices) works *only* for arrays and falls down for collections. This is similar to the problem which motivates removal of `enumerated()` as discussed in other threads. In this case, it is not guaranteed that a collection with indices `0..&lt;10` has an index 9.</div><div><br></div></div></div></blockquote><div><br></div><div>You make a good point, but then how exactly did the range-clamping function make it into the standard library in the first place? I can&#39;t think of frequent reason to want to clamp a range to within another range putting my mind to it, yet a clamp function on the Bound type has uses with arrays and offers a clear improvement to readability. Then there&#39;s the (potential) correctness trap of mixing up min and max, which I find leads me to need to double-check the logic after typing.</div><div><br></div><div>Seeing those criteria just makes it all the more frustrating that the range-clamping version is the one to have made the cut.</div></div></blockquote><div><br></div></span><div>Rereading, you&#39;re point is that the range-clamping version does solve a correctness trap (and that the Bound version does not?). Could you explain how you reached to this conclusion?</div></div></blockquote><div><br></div><div>I&#39;m not making that point. I&#39;m just pointing out that these are the current criteria for expanding the standard library.</div><div><br></div><div>If, looking back, you feel that the existing `clamped(to:)` doesn&#39;t fit the criteria, then you can propose its removal. However, there are also standards for changing existing APIs in Swift 4. The first one is that &quot;the existing syntax/API being changed must be actively harmful&quot;--which is a bar that `clamped(to:)` doesn&#39;t meet, IMO.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div dir="auto"><span class="gmail-"><blockquote type="cite"><div><blockquote type="cite"><div><div dir="ltr">On Fri, Mar 10, 2017 at 4:48 PM, James Froggatt via swift-evolution <span dir="ltr">&lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;</span> wrote:<br><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">This topic caught my attention. I support the idea, I&#39;m currently using an extension for this.<br>
<span class="gmail-m_-4814290136450491565gmail-"><br>
&gt;&gt;Should “16.clamped(to: 0..&lt;10)” produce 9 or 10?<br>
<br>
&gt;9<br>
<br>
</span>Sounds good.<br>
<span class="gmail-m_-4814290136450491565gmail-"><br>
&gt;&gt;What about “16.clamped(to: 0..&lt;0)”, which is an empty range?<br>
<br>
&gt;For `Int`? Crash (which, until about 5 minutes ago, is what I thought would happen if you tried to create a range that’s empty like that). For types that support it, I’d say NaN or something like “nil”/“empty” is the most appropriate return value<br>
<br>
</span>Nasty but reasonable. I&#39;d support it returning nil in this case, this would provide a warning that the result may not be a valid number, as well as providing this elegant range validation:<br>
<br>
`if let index = candidate.clamped(to: array.indices) { … }`<br>
<br>
(or a possible alternative spelling:)<br>
<br>
`if let index = array.indices.clamp(candidate) { … }`<br>
<span class="gmail-m_-4814290136450491565gmail-"><br>
&gt;&gt;Does “16.0.clamped(to: 0..&lt;10)” yield 10.0 or the next-smaller representable Double?<br>
<br>
&gt;Next-smaller, IMHO. It’s not exactly semantically correct, but AFAIK that’s as correct as Float/Double can be.<br>
<br>
</span>One could argue the most ‘correct’ value here is the closest representation of the theoretical value, `10.0 - (1 / ∞)`, which should clearly round to 10. However, this also rounds the result back out of the range, meaning it&#39;s unsuitable as a result. Both possibilities are, for lack of a better word, ugly.<br>
<span class="gmail-m_-4814290136450491565gmail-"><br>
&gt;Mostly though I’d really like to be able to clamp to array indices, which are pretty much always written as a `Range`, rather than a `ClosedRange`. We could write the function for `Range` to only be generic over `Comparable&amp;Integer`, if the floating point corner cases are too much.<br>
<br>
&gt; - Dave Sweeris<br>
<br>
</span>My conclusion also. I&#39;d like to see this added to the standard library, if it&#39;s in scope for Swift 4.<br>
<br>
Sidenote: I can&#39;t help but think index validation would be better solved in many cases by an optional-returning array subscript (`array[ifPresent: index]`), but I&#39;ve seen this solution turned down several times due to the lack of discoverability (read: lack of Xcode autocompletion, which I originally thought was a bug until it stayed that way for ~3 years). I&#39;d also like to see this feature get added in some form, eventually.<br>
<div class="gmail-m_-4814290136450491565gmail-HOEnZb"><div class="gmail-m_-4814290136450491565gmail-h5">______________________________<wbr>_________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailma<wbr>n/listinfo/swift-evolution</a><br>
</div></div></blockquote></div><br></div></div>
</div></blockquote></div></blockquote></span></div></blockquote></div><br></div></div>