Repository navigation
Tracking Issue for clamp_to #147781
Copy link
Copy link
Open
Labels
C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCCategory: An issue tracking the progress of sth. like the implementation of an RFCS-tracking-unimplementedStatus: The feature has not been implemented.Status: The feature has not been implemented.T-libsRelevant to the library team, which will review and decide on the PR/issue.Relevant to the library team, which will review and decide on the PR/issue.
Description
Feature gate: #![feature(clamp_to)], as well as possibly perma-unstable #[feature(clamp_bounds)].
This is a tracking issue for rust-lang/libs-team#665, which adds less confusable alternatives for x.min(y) and x.max(y).
Public API
// Perma-unstable
trait ClampBounds<T> {
fn clamp(self, x: T) -> T;
}
impl ClampBounds<T> for RangeInclusive<T> where T: Ord {}
impl ClampBounds<f32> for RangeInclusive<f32> {}
// likewise for RangeFrom, RangeToInclusive, and RangeFull, and for f16/f64/f128
trait Ord {
fn clamp_to(self, range: impl ClampBounds<Self>) -> Self;
}
// For each floating-point type:
impl f32 {
fn clamp_to(self, range: impl ClampBounds<Self>) -> Self;
}Steps / History
(Remember to update the S-tracking-* label when checking boxes.)
- ACP: ACP: Intuitive alternative for
.min()and.max()libs-team#665 - Implementation 1: Implement clamp_min and clamp_max #147786
- Implementation 2: Implement clamp_to #150075
- Final comment period (FCP)1
- Stabilization PR
Unresolved Questions
Is having these functions, where clamp_min == max, actually less confusing than the status quo?- It is not. Switched to
clamp_towith ranges.
- It is not. Switched to
- Should there be a lint that suggests replacing
x.max(y)withx.clamp_to(y..)? - What semantics should the float versions have regarding NaN?
NAN.max(0.0)is 0, whileNAN.clamp(0.0, 0.0)is NaN, and0.0.clamp(NAN, NAN)panics.
Footnotes
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCCategory: An issue tracking the progress of sth. like the implementation of an RFCS-tracking-unimplementedStatus: The feature has not been implemented.Status: The feature has not been implemented.T-libsRelevant to the library team, which will review and decide on the PR/issue.Relevant to the library team, which will review and decide on the PR/issue.
Activity
Kyuuhachi commentedon Oct 16, 2025
I'm adding NaN semantics to unresolved questions. Current implementation has same as
.max(), but it would also make sense to have the same semantics as.clamp().ChrisDenton commentedon Oct 17, 2025
On the original zulip thread, simulacrum suggested naming these
at_mostandat_least, which would avoid the slightly confusing naming whereclamp_maxdoes the opposite tomax.clarfonthey commentedon Oct 19, 2025
I don't really like the idea of having two methods that do exactly the same thing with different names. I think it's reasonable to deprecate a name in favour of a new one, but not just have two concurrent names at the same time.
I agree that
at_mostandat_leastare more understandable than the current names and might actually be an improvement, but I would much rather have something likeclamp_into(range)than a pair of methods, so there's actually the additional benefit of showing the range instead, although you would have to be careful to explicitly disallow exclusive ranges.joboet commentedon Oct 21, 2025
I too favour the originally proposed
clamp_range, especially as it corresponds nicely with the notion of a "valid value range".ChrisDenton commentedon Oct 21, 2025
Using range types was discussed In the libs-api meeting but team members weren't generally favourable. From memory I think the concern was the added complexity especially considering the fact that most people would be looking to clamp only one side.
This was also a concern raised in the meeting. But experimenting with it in nightly was deemed acceptable.
boomshroom commentedon Oct 21, 2025
Oh, so I guess we should get rid of
clampthen, since it clamps from both sides?Using a range type makes it more obvious that 1-sided clamps from either side and 2-sided clamps are fundamentally the same operation.
ChrisDenton commentedon Oct 22, 2025
No, the fact that
clampexists and nobody has taken issue with it suggests it doesn't need a range replacement.clarfonthey commentedon Oct 22, 2025
I think that having different names for the versions with different calling conventions is fine, but we can't limit the calling conventions of methods at the moment. Perhaps a good path forward if we do choose to pursue this path is to have a clippy lint (I only propose clippy because it has MSRV support, which rustc lints do not), which suggests reformatting
x.min/max(y)intox.clamp_max/min(y)andOrd::clamp_min/max(x, y)intoOrd::max/min(x, y). I think this shouldn't be machine-applicable because we want to verify that the user was actually using the right version, and so they should have to manually fix it.Rollup merge of rust-lang#147786 - Kyuuhachi:clamp-min-max, r=joboet
Rollup merge of rust-lang#147786 - Kyuuhachi:clamp-min-max, r=joboet
Rollup merge of rust-lang#147786 - Kyuuhachi:clamp-min-max, r=joboet
orlp commentedon Dec 16, 2025
I think the names
clamp_minandclamp_maxare actively harmful. They only further amplify the original motivation for the ACP, rather than solve it:Before this was simply a problem for beginners, a mistake you make a couple times before realizing that that is not how
min/maxwork. You adjust and move on.With the introduction of
clamp_minandclamp_max... we've now reified the actual confusion! What used to just be a mistake rooted in imagination is now an actual real function under a subtly different name!I would strongly recommend the adoption of a name which does not include
minormax. I would suggest either.clamp_at_most(x)/.clamp_at_least(x).at_most(x)/.at_least(x)14 remaining items
Rollup merge of rust-lang#150075 - Kyuuhachi:limit_to, r=ChrisDenton
Rollup merge of rust-lang#150075 - Kyuuhachi:limit_to, r=ChrisDenton
Rollup merge of rust-lang#150075 - Kyuuhachi:limit_to, r=ChrisDenton
Rollup merge of rust-lang#150075 - Kyuuhachi:limit_to, r=ChrisDenton
Rollup merge of rust-lang#150075 - Kyuuhachi:limit_to, r=ChrisDenton
Rollup merge of rust-lang#150075 - Kyuuhachi:limit_to, r=ChrisDenton
Rollup merge of rust-lang#150075 - Kyuuhachi:limit_to, r=ChrisDenton
Rollup merge of rust-lang#150075 - Kyuuhachi:limit_to, r=ChrisDenton
Rollup merge of rust-lang#150075 - Kyuuhachi:limit_to, r=ChrisDenton
Rollup merge of rust-lang#150075 - Kyuuhachi:limit_to, r=ChrisDenton
Rollup merge of rust-lang#150075 - Kyuuhachi:limit_to, r=ChrisDenton
Rollup merge of rust-lang#150075 - Kyuuhachi:limit_to, r=ChrisDenton
Rollup merge of rust-lang#150075 - Kyuuhachi:limit_to, r=ChrisDenton
Rollup merge of rust-lang#150075 - Kyuuhachi:limit_to, r=ChrisDenton
Unrolled build for #150075 in rollup 161906