-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
RFC: Add std::num::NonZeroU32 and friends, deprecate core::nonzero #2307
Conversation
Not featured in the RFC because I couldn’t find a way to express it more objectively: I think the |
A more general approach would use |
@eddyb Is this an argument against adding non-zero integer types? I’d like to keep details of a more general feature out of scope for this PR, thanks :) |
Yes, if const generics were further along, I'd be more against this RFC. As it stands, a mention in alternatives is probably enough. |
I would argue that
Are non-zero integers actually used in practice to justify stabilizing these types? I have only ever seen |
I think @stoklund also used the max value in Cranelift, and the Rust compiler itself has a few types for which that's a dummy. So maybe we can defer this until a more general approach can be tried out. |
Servo has a few types like These could likely just as well have |
If this is an argument for rejecting this RFC one question is: who’s volunteering for championing the designing and RFC and implementation for that more general feature? |
Agree that hardcoding the sentinel value to zero seems limiting. Also agree that waiting for const generics seems like a showstopper (and might also end up overengineered). Is there any reason this has to be in core/std? Looking at the example implementation in the RFC, it looks like all of this is using stable features and could easily exist in a third-party crate. If possible, that seems like the way to go. |
@bstrie The compiler has to be told what the invalid values are - hence |
@bstrie A wrapper type that maintains invariant in order to help with some algorithm’s correctness can be outside of |
Ah, I glossed over the non_zero lang item there... figured that this implementation was taking advantage of some of the new enum niche optimizations somehow. Is a new lang item really preferable to stabilizing the Zeroable trait? (I see a lot of dislike for Zeroable in rust-lang/rust#27730, but not much explicit discussion of its downsides.) |
@bstrie The I’d forgotten to list the stabilizing |
I am coming from this Reddit where I basically asked for unsigned integer types without zero. I am using the term natural number to refer to ℕ⁺ = {1, 2, …}, hence, excluding zero, which I refer to as whole numbers ℕ⁰ = {0, 1, 2, …}. I see great value in the addition of these types to Rust and have many use cases where they are useful. I do not know how |
@Fleshgrinder struct BoundedU32<const LOWER_BOUND: u32, const UPPER_BOUND: u32>(/* … */); Then natural integers (up to bit storage capacity) become just a special case that you could define in your crates: type NonZeroU32 = BoundedU32<1, u32::MAX>; |
I figured, well, that would definitely be better than having dedicated types due to the flexibility they offer. |
It seems to me that there are two different requests here:
I am not sure that mixing them is the right approach. For example, imagine that I create two types: I would not be able to use a It seems that for the case of enum layout optimization, relying on
The nice thing about functions being that they are easily composed. For example, the implementation for |
So I was playing a little with the nightly The situation would be the same with |
@SimonSapin "Bounded" is the opposite of what you want (unless you make it wrap around, which would be confusing but equivalent in power) i.e. your example would be @matthieu-m Using anything other than a single range per enum requires potentially expensive rewrites when the enum discriminant is ever operated on. We could be tracking multiple ranges and pick a contiguous piece of them for each Even/odd is more interesting problem, pretty similar to taking advantage of pointer alignment. struct InvalidRange {
offset: usize,
size: usize,
range: RangeInclusive<u128>
}
trait HasInvalid {
const fn next_invalid(previous: Option<InvalidRange>) -> Option<InvalidRange>;
} |
I started it, but this is getting into the details of designing a feature that is not the one proposed in this RFC. Please let’s keep this thread about this proposal. We can discuss the existence of a potential more general feature as an argument for rejecting this RFC, without going into the details of how exactly that other feature works. (Though once again I am not making that argument. We can do both.) If someone does want to follow through discussing these details, please consider making a separate RFC or forum thread. |
The non-orthogonality of this proposal seems somewhat unsatisfying. What if some day someone wishes to have an |
On Even if we made |
Okay, atomics are a bad example. My point was a little more abstract, though: eliminating genericity may make it harder/impossible to simultaneously forbid zero values and use other features. It may be the case that this genericity is not worth the trouble (I'm not especially aware of all the trade-offs involved), but I think it's at least worth thinking about. |
Maybe it would be better to implement the non-zero types as primitives, like I expected them to be, in that case, atomics would work like the work right now with the others. I honestly never thought about an integer without zero and fail to see the use case, however, for real natural numbers it should be quite easy to define such a primitive type. |
The main use case is using
Why? I don’t think having
I don’t understand, you explain some more what you mean here? (At the moment we have |
Integer: {-∞, …, -2, -1, 0, 1, 2, …, ∞} What I said is that I fail to see the use case for non-zero integers (hence {-∞, …, -2, -1, 1, 2, …, ∞}) but that I see the use case for non-zero unsigned integers (Natural Number; hence {1, 2, …, ∞}). The latter is what applies to identifiers (usually) and is the use case I am coming from. With primitives I meant |
Ah ok. Yes, the |
@joshtriplett Agreed! I think it should be listed as an unresolved question and hence recorded on the tracking issue. |
@rfcbot fcp merge |
Team member @aturon has proposed to merge this. The next step is review by the rest of the tagged teams: No concerns currently listed. Once a majority of reviewers approve (and none object), 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. |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
Bikeshed: how about Edit: I also like |
The fact that “positive” does not include zero in English is something that I’ve learned a couple years ago but it is still subtle in my mind. This is not the case in French, “nombre positif” correctly translates to “non-negative number”. Relying on such a subtle (at least to some parts of the world) aspect of what “positive” means to express the core property of these types doesn’t sound great to me. |
This is the usual meaning in programming, though. For example,
And overall, |
|
The final comment period is now complete. |
Huzzah! This RFC has been accepted. Tracking issue: rust-lang/rust#49137 |
FWIW, even though I'm aware that "positive" technically excludes zero, whenever a non-mathematician says "positive" I don't feel safe assuming that they really meant to exclude zero, because so many people use positive/negative colloquially without thinking about the zero case. Even if I was reading a language spec that used the word "positive", unless there was an explicit mention of zero or non-negative/non-positive very close by (which is the case in all of @scottmcm's links), I'd feel the need to double-check that I hadn't discovered an unintentional underspecification. So I think |
@Ixrec I agree, but since this RFC is merged further discussion should probably go into the tracking issue: rust-lang/rust#49137 |
Add 12 num::NonZero* types for primitive integers, deprecate core::nonzero RFC: rust-lang/rfcs#2307 Tracking issue: ~~rust-lang#27730 rust-lang#49137 Fixes rust-lang#27730
Add 12 num::NonZero* types for primitive integers, deprecate core::nonzero RFC: rust-lang/rfcs#2307 Tracking issue: ~~rust-lang#27730 rust-lang#49137 Fixes rust-lang#27730
Add
std::num::NonZeroU32
and eleven other concrete types (one for each primitive integer type) to replace and deprecatecore::nonzero::NonZero<T>
. (Non-zero/non-null raw pointers are available throughstd::ptr::NonNull<U>
.)Rendered
Tracking issue