2020. The extremely simple way.
extension Comparable {
func clamped(_ f: Self, _ t: Self) -> Self {
var r = self
if r < f { r = f }
if r > t { r = t }
// (use SIMPLE, EXPLICIT code here to make it utterly clear
// whether we are inclusive, what form of equality, etc etc)
return r
}
}
While I truly love ranges in Swift, I really think the absolutely standard syntax for a clamp function ("for 50 years now in every computer language") is just simpler and better:
x = x.clamped(0.5, 5.0)
Until it is built-in to Swift, really I think that's best.
Philosophical corner:
IMO the two values in a clamp function are not really a 'range' - they're just "two values".
(Just for example: it's completely common in game code to have the two dynamic values sometimes be in the "wrong order" (i.e., the desired result is something outside) or the same (the result is just that value).)
An opinion on end-naming ...
On everything we do, we insist on explicitly stating whether inclusive or exclusive. For example if there's a call
randomIntUpTo( 13 )
in fact we will name it
randomIntUpToExclusive( 13 )
or indeed "inclusive" if that is the case. Or depending on the language something like
randomInt(fromInclusive: upToExclusive: )
or whatever the case may be. In this way there is absolutely never ever ever a unity error, and nothing needs to be discussed. All code names should be self-documenting. So indeed, for us, the function above would be named
func clamped(fromExclusive: Self, toExclusive: Self)
or whatever describes it.
But that's just us. But it's the right thing to do :)