> On Mar 10, 2017, at 8:04 PM, Robert Bennett via swift-evolution 
> <[email protected]> wrote:
> 
> I really like this proposal, and think that it does have a place in Swift 4. 
> Two quick notes in light of the discussion: first, I think it should be 
> called clamped, not clamp; second, I think it should only take ClosedRange. 
> More on those later, but first I'll respond to the six questions raised by 
> Xiaodi.
> 
>> 1. Is it truly a frequent operation?
> I think so. I've certainly wished for it on an occasion or two. I settle for 
> min(upper, max(lower, value)).
> 
>> 2. Is the helper more readable? Is the composed equivalent obvious at a 
>> glance?
> Definitely (or I imagine it will be once we get the details figured out). 
> There are two equivalent forms of the min-max version, the other being 
> max(lower, min(upper, value)), not to mention the commutativity of the 
> arguments themselves. I am under the impression that Swift is not a big fan 
> of having multiple equivalent ways to do the same thing — that was part of 
> the reason ++ was nixed. value.clamp(to: closedRange) is clear and is not 
> interchangeable with any one thing in the language.
> 
>> 3. Does the helper have the flexibility to cover all common cases?
> I see three cases: value < lower, lower <= value <= upper, and upper < value. 
> All are covered.
> 
>> 4. Is there a correctness trap with the composed equivalent? Is there a 
>> correctness trap with the helper?
> I don't think so, if we limit to ClosedRange.
> 
>> 5. Is there a performance trap with the composed equivalent? Or with the 
>> helper?
> I don't know, is there a significant cost associated to constructing a 
> ClosedRange solely for the purpose of using its bounds? I would imagine not, 
> but someone who knows more about Swift can answer.
> 
>> 6. Does the helper actually encourage misuse?
> I don't see how, if we limit its argument to ClosedRange.
> 
> 
> Going back to my earlier points — I think that to keep things in line with 
> Swift's naming conventions, this function should be called clamped, as it 
> returns a modified version of the calling object. Alternatively, we could 
> follow the standard set by other numeric types and provide the non-mutating 
> clamped and the mutating clamp, like multiplied/multiply for Double.
> 
> Finally, I don't think it makes mathematical sense to clamp to a non-closed 
> range. Refer back to the original definition proposed, `min(upperBound, 
> max(lowerBound, value))`. ClosedRange was proposed as a convenience for 
> providing those bounds. This makes sense because a ClosedRange contains its 
> bounds. Since (mathematical) non-closed ranges don't contain their bounds, it 
> doesn't make sense to use a non-closed range to provide those bounds.

I think open ranges should be supported, but not for all `Comparable` types. It 
would however be reasonable to support it for types with discrete ordered 
values, all `Integer` types for example. I think we might be able to provide it 
for `T: Strideable where T.Stride: Integer` even. We definitely cannot provide 
it for all types though; it’s nonsensical to clamp a real value to a closed 
range.

> 
> Also, the above notwithstanding, I have a hard time figuring out when you 
> would actually want to constrain a number to be strictly less than an upper 
> bound, violating Question 1 above. If this behavior were really desired, 
> better to be explicit and subtract the appropriate delta — 1 for Int, 
> Double.epsilon (or whatever it's called) for Double. I definitely foresee a 
> correctness trap with the non-closed Range.
> 
> Another reason not to allow half-open ranges is because of their asymmetry. 
> Half open ranges are only open at their upper end, so you would have the 
> ability to open-clamp from above but not from below. Seems arbitrary (see 
> Question 3).

We already have this asymmetry. Adding a clamp function doesn’t worsen it. 
Besides, we have half-open [above] ranges because they are useful for indices:

`arr[idx.clamped(to: arr.startIndex..<arr.endIndex)`

We can even write this!

`arr[idx.clamped(to: arr.indices)]`

This seems like a useful enough feature to consider it IMO.

> 
> _______________________________________________
> swift-evolution mailing list
> [email protected]
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to