Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add NonZero{I,U}{8,16,32,64,128,size}::{MIN,MAX} #89065

Closed
EFanZh opened this issue Sep 18, 2021 · 17 comments · Fixed by #106633
Closed

Add NonZero{I,U}{8,16,32,64,128,size}::{MIN,MAX} #89065

EFanZh opened this issue Sep 18, 2021 · 17 comments · Fixed by #106633
Assignees
Labels
C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.

Comments

@EFanZh
Copy link
Contributor

EFanZh commented Sep 18, 2021

Currently, there is no way to obtain a NonZero* value without introducing unsafe codes or unwrap() calls, providing these constants can make it easier to use these types. For example:

use std::num::NonZeroU64;

fn foo(x: u64) -> NonZeroU64 {
    x.checked_add(1).and_then(NonZeroU64::new).unwrap_or(NonZeroU64::MAX)
}
@mjclements
Copy link

I think this sounds like a good feature, and I would like to claim it for a first contribution.

@mjclements
Copy link

@rustbot claim

@LingMan
Copy link
Contributor

LingMan commented Sep 19, 2021

Not that I mind the addition of these constants in general, but your motivating example is a bit unfortunate in that it's a slightly obfuscated saturating_add. It would be better served by:

#![feature(nonzero_ops)]
use std::num::NonZeroU64;

pub fn baz(x: u64) -> NonZeroU64 {
    NonZeroU64::new(1).unwrap().saturating_add(x)

    // or `NonZeroU64::new(x.saturating_add(1)).unwrap()` if you need a solution on stable
}

Yes, that does contain an unwrap, but it's provably unreachable and really the right tool for the job here. (Slightly better codegen too https://rust.godbolt.org/z/Tansn3Y61)

@EFanZh
Copy link
Contributor Author

EFanZh commented Sep 19, 2021

There are projects that forbid the usage of unwrap with Clippy. Using unwrap will require explicit #[allow(...)] attribute and maybe proper comment, which seems a little too much.

@mjclements
Copy link

This might just be my head being in a more Ada space, but not having immediate access to the MIN and MAX for a given scalar type feels wrong to me. Obviously with a little forethought you can come up with a totally safe unwrap, but when you're doing something simple like initializing values for a comparison algorithm, it seems like it might be a bit better if you can use a constant which took care of that thinking about safety for you.

@LingMan
Copy link
Contributor

LingMan commented Sep 20, 2021

@mjclements: Thank you. This:

but when you're doing something simple like initializing values for a comparison algorithm

is a good motivating example if you ask me.

@EFanZh: Sounds like these projects blanket forbid unwrap as a very coarse heuristic for the behavior they actually want to disallow. If this unwanted behavior is "there is an input that causes the program to panic (ignoring OOM)", you could teach Clippy to allow unwrap in const contexts. That way you get a compilation error if the panic path ever fires. The example you provided would then look like:

#![feature(nonzero_ops)]
#![feature(const_option)]
use std::num::NonZeroU64;

pub fn bax(x: u64) -> NonZeroU64 {
    const ONE: NonZeroU64 = NonZeroU64::new(1).unwrap();
    ONE.saturating_add(x)
}

Of course that currently requires nightly features and not sure how hard it would be to improve Clippy. Hopefully that will become viable for stable projects soon.

@kpreid
Copy link
Contributor

kpreid commented Sep 20, 2021

Some interrelated thoughts on the stated problems this is trying to solve:

  • NonZeroI*::{MIN,MAX} are a little weird, because in all other integer cases, all integers between MIN and MAX exist, but in the case of nonzero signed integers, there's also a hole in the middle. This seems an oddity worth thinking about and possibly documenting.

  • I also notice that the code example at the beginning of this thread cannot be written using these constants for NonZeroI* because while NonZeroU*::MIN is 1, NonZeroI*::MIN is not. Also the code would be clearer in both cases if the value was named ONE rather than MIN. This suggests to me that possibly there should be a ONE constant for NonZero types, or at least the signed ones.

    • If there were to be ONE, then the question of why not TWO, TEN, etc. comes up. The plausible response to adding any of them is "it's all moot once const panics are stable", but NonZeroI64::new(5).unwrap() is still a long and tedious bit of code to write whenever you want a number literal. It would be nice if there was a specific or general way to improve such fallible-but-only-at-compile-time code. (I have some thoughts on this but they're further off-topic for this issue.)

(None of this is intended to argue that MIN and MAX shouldn't be added.)

@mjclements
Copy link

I like the points @kpreid made. I would concur that ONE as a constant might be useful, but should not be instead of a MIN, even for the signed integers. I think having the lowest possible value clearly demarcated as such has value.

(It would be kinda nice to have a fast way of making number literals of this type. I think that would probably help with adoption. Feel free to tag me if you open an issue!)

@LingMan
Copy link
Contributor

LingMan commented Sep 21, 2021

  • NonZeroI*::{MIN,MAX} are a little weird, because in all other integer cases, all integers between MIN and MAX exist, but in the case of nonzero signed integers, there's also a hole in the middle. This seems an oddity worth thinking about and possibly documenting.

Agreed.

  • I also notice that the code example at the beginning of this thread cannot be written using these constants for NonZeroI* because while NonZeroU*::MIN is 1, NonZeroI*::MIN is not. Also the code would be clearer in both cases if the value was named ONE rather than MIN. This suggests to me that possibly there should be a ONE constant for NonZero types, or at least the signed ones.

Not sure I follow. The code example at the beginning used MAX and not MIN. Yes, it does happen to add 1 - which incidentally also happens to be the value of NonZeroU*::MIN - so you technically could implement the given example as:

use std::num::NonZeroU64;

pub fn bax(x: u64) -> NonZeroU64 {
    NonZeroU64::MIN.saturating_add(x)
}

Luckily, I haven't seen anybody propose such a gross abuse of the MIN constant.

  • If there were to be ONE, then the question of why not TWO, TEN, etc. comes up. The plausible response to adding any of them is "it's all moot once const panics are stable", but NonZeroI64::new(5).unwrap() is still a long and tedious bit of code to write whenever you want a number literal. It would be nice if there was a specific or general way to improve such fallible-but-only-at-compile-time code. (I have some thoughts on this but they're further off-topic for this issue.)

Yes, getting a literal NonZero* is currently overly clunky and should be made easier and quicker. No doubt about that, but adding otherwise meaningless constants (be it ONE or TWO or TEN) isn't a good solution. Not sure how solutions could look that that are both ergonomic and feasible, but that's indeed going too far off-topic. If you end up writing down your thoughts on that, kindly cc me.

Dylan-DPC added a commit to Dylan-DPC/rust that referenced this issue Mar 11, 2022
Implement `MIN`/`MAX` constants for non-zero integers

This adds the associated [`MIN`](https://doc.rust-lang.org/stable/std/primitive.usize.html#associatedconstant.MIN)/[`MAX`](https://doc.rust-lang.org/stable/std/primitive.usize.html#associatedconstant.MAX) constants to `NonZero{U,I}{8,16,32,64,128,size}`, requested in rust-lang#89065.

This reimplements rust-lang#89077 due that PR being stagnant for 4 months. I am fine with closing this in favor of that one if the author revisits it. If so, I'd like to see that PR have the docs link to the `$Int`'s constants.
@nvzqz
Copy link
Contributor

nvzqz commented Mar 12, 2022

This is now available on nightly (docs).

@EFanZh EFanZh changed the title Add NonZero{I,U}{8,16,32,64,128}::{MIN,MAX} Add NonZero{I,U}{8,16,32,64,128,size}::{MIN,MAX} Mar 15, 2022
@gilescope
Copy link
Contributor

Excellent, glad these have landed. Am discussing having these MIN/MAX available from traits:
https://internals.rust-lang.org/t/please-can-we-add-a-basic-num-trait/16449/9

@c410-f3r
Copy link
Contributor

Is there anything blocking the stabilization of this feature?

@c410-f3r
Copy link
Contributor

I guess this feature is simple and mature enough for stable toolchains.

@nvzqz Are you willing to create a stabilization report?

@dtolnay dtolnay added T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC labels Jan 23, 2023
@rfcbot
Copy link

rfcbot commented Jan 23, 2023

Team member @dtolnay has proposed to merge this. The next step is review by the rest of the tagged team members:

No concerns currently listed.

Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

See this document for info about what commands tagged team members can give me.

@rfcbot rfcbot added proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. labels Jan 23, 2023
@rfcbot rfcbot added final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. and removed proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. labels Feb 28, 2023
@rfcbot
Copy link

rfcbot commented Feb 28, 2023

🔔 This is now entering its final comment period, as per the review above. 🔔

@rfcbot rfcbot added finished-final-comment-period The final comment period is finished for this PR / Issue. to-announce Announce this issue on triage meeting and removed final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. labels Mar 10, 2023
@rfcbot
Copy link

rfcbot commented Mar 10, 2023

The final comment period, with a disposition to merge, as per the review above, is now complete.

As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed.

This will be merged soon.

matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Mar 11, 2023
…=dtolnay

Stabilize `nonzero_min_max`

## Overall

Stabilizes `nonzero_min_max` to allow the "infallible" construction of ordinary minimum and maximum `NonZero*` instances.

The feature is fairly straightforward and already matured for some time in stable toolchains.

```rust
let _ = NonZeroU8::MIN;
let _ = NonZeroI32::MAX;
```

## History

* On 2022-01-25, implementation was [created](rust-lang#93293).

## Considerations

* This report is fruit of the inanition observed after two unsuccessful attempts at getting feedback.
* Other constant variants discussed at rust-lang#89065 (comment) are orthogonal to this feature.

Fixes rust-lang#89065
@bors bors closed this as completed in ffc0b8a Mar 11, 2023
@apiraino apiraino removed the to-announce Announce this issue on triage meeting label Mar 23, 2023
thomcc pushed a commit to tcdi/postgrestd that referenced this issue Jun 1, 2023
Stabilize `nonzero_min_max`

## Overall

Stabilizes `nonzero_min_max` to allow the "infallible" construction of ordinary minimum and maximum `NonZero*` instances.

The feature is fairly straightforward and already matured for some time in stable toolchains.

```rust
let _ = NonZeroU8::MIN;
let _ = NonZeroI32::MAX;
```

## History

* On 2022-01-25, implementation was [created](rust-lang/rust#93293).

## Considerations

* This report is fruit of the inanition observed after two unsuccessful attempts at getting feedback.
* Other constant variants discussed at rust-lang/rust#89065 (comment) are orthogonal to this feature.

Fixes rust-lang/rust#89065
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

10 participants