Revisiting SE-0177: Adding `clamped(to:)`

It has been a while since SE-0177 was sent back for revision (three years?) and it
might be worth it to start a new thread here about what to do with SE-0177.

At the moment I have one pull request for the Swift Evolution repository and another pull request adding clamped as an extension on Comparable to the standard library.

I would love to start this discussion with everyone about what to do next until SE-0177 is complete.


Swift Evolution PR:

Swift pull request:


I’m a bit hesitant to add functions to every Comparable, because it’s quite a common protocol. For example, String is Comparable, and it makes sense to compare them; but does it make sense to clamp a String? I’m not sure that’s an incredibly useful operation, so I’m not sure it’s worth adding this to every Comparable type.

Did you consider a clamp free function?

EDIT: I didn’t read the feedback from the last round of review, but I would expect some summary and rationale of any controversial design aspects to be included in the proposal’s “alternatives considered” section. Otherwise, since it says no alternatives were considered, I’m literally assuming you didn’t consider a free function.

1 Like

Actually I am not against adding a free function at all, max and min work much like this would so a free function is very suitable I think.

The reason why I didn't take that path is that in 2017 some members of the core team suggested not increasing the number of global functions thus the current proposal.

How does everyone feel about clamp as a free function? If there is enough support, could just rewrite everything as a free function version of clamp.

I prefer the extension. It reads more like natural language to me. IMO It fits more with the existing APIs. It doesn't "pollute the global namespace," as they say. I've been using the extension on Comparable in my code for a few years now. I suspect a lot of people have been doing so.

let x = y.clamped(to: z)
let x = clamp(y, to: z)

Speaking of alternatives, and not because I'm particularly fond of this:

There are the existing .init(clamping:) initializers that clamp some value of a type with larger range to the range of the type being initialized, eg:

let someByte = UInt8(clamping: someInt32OrSomething)

Along similar lines, the proposed method(s) could be on ClosedRange, PartialRangeThrough and PartialRangeFrom (instead of on Comparable):

let a = (b...c).clamping(d)
let a = (b...).clamping(d)
let a = (...c).clamping(d)

I do think it feels a bit backwards compared to a = d.clamped(to: b...c) but it could still be among the considered alternatives I guess, and it raises the question of whether the "clampee", limits and result should all be the same type or if the type of the limits and result should be a type parameter, to allow clamping eg an Int32 value to an Int8 value within -10...10.


Yeah extension seems a bit more natural.
What would really be the downsides of adding it onto Comparable?
I don't think it would really pollute the namespace.

Terms of Service

Privacy Policy

Cookie Policy