-
Notifications
You must be signed in to change notification settings - Fork 13.1k
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Implement nonzero arithmetics for NonZero types. #82703
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @kennytm (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the PR ! It's very well done, I left some comments, mostly about doc improvements, the code looks good to me.
I'm would instinctively think checked_add would receive a NonZero* type, but that's only my feeling. Using a generic over Into<$Int> is possible here, but that's probably overkill for an addition.
It'll also allow a whole bunch more things than is probably wanted, like It could potentially use a new pub-trait-in-private-module to accept just |
I had initially thought about
This said, I agree that it seems weird at first, especially because these three signatures are inconsistent:
But I think it's easy enough to explain why it is the case. |
This comment has been minimized.
This comment has been minimized.
r? @dtolnay |
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like a good addition to try out. Can you open a tracking issue? Thanks!
(You can use the same feature gate for all of them, maybe nonzero_checked_ops
or something like that.)
@m-ou-se Okay. Since you also offer to implement I have no particular inclusion criterion yet (any idea?), but I'll exclude every operation for which it is possible to get a null result without overflowing the type. This rules out I'll make sure all tests pass and the new "ops" undergo revision again before I open the tracking issue. |
This one's a bit unfortunate, overflowing for about half the values. That's why it's implemented with But I guess that's a different PR's problem. I suppose |
An important logistical note, @iago-lito: you'll probably want to put methods (like So |
@scottmcm Okay, I think I understand the need for a separate PR. I have scanned methods of
I have tried to only omit byte-level operations. All these (if accepted) would be gathered behind the feature gate To clear things up, the advantage of implementing these methods is to save a check and replace the unsafe and verbose, say unsafe { NonZeroU8::unchecked_new(nz.get().saturating_add(nz.get())) } by nz.saturating_add(nz) However, note that [EDIT]: Following @scottmcm comment, withdraw the above methods from the list for this reason, except for |
Good survey!
I think this is an important consideration. If the And I agree that if one is already using unsafe code to call But maybe it would be ok to have |
@scottmcm Thank you for feedback :) We seem to agree with the reasoning, so I have withdrawn methods which do not save a check or the need for unsafe code from the list.
Agreed. For this reason, If it sounds okay to you, I'll jump into implementation soon :) |
(github-related question: I have updated the PR title so it better matches the extended implementation plan, but the corresponding branch is still poorly named, is that a problem or not at all?) |
(Don't worry about the branch name. There's actually quite a few contributors who put jokes or puns in their branch names, or just something random. It's fine.) |
@bors r=m-ou-se |
📌 Commit 7afdaf2 has been approved by |
⌛ Testing commit 7afdaf2 with merge 18a20b8311dd63a78420c7065eeb2f6baec2b9ae... |
The job Click to see the possible cause of the failure (guessed by this bot)
|
💔 Test failed - checks-actions |
@bors retry spurious network error:
|
⌛ Testing commit 7afdaf2 with merge 705f1a35911507e5a5bdef7746d19eb02aee2f8b... |
💔 Test failed - checks-actions |
@bors retry |
☀️ Test successful - checks-actions |
Hello'all, this is my first PR to this repo.
Non-zero natural numbers are stable by addition/multiplication/exponentiation, so it makes sense to make this arithmetic possible with
NonZeroU*
.The major pitfall is that overflowing underlying
u*
types possibly lead to underlying0
values, which break the major invariant ofNonZeroU*
. To accommodate it, onlychecked_
andsaturating_
operations are implemented.Other variants allowing wrapped results like
wrapping_
oroverflowing_
are ruled out de facto.impl Add<u*> for NonZeroU* { .. }
was considered, as it panics on overflow which enforces the invariant, but it does not so in release mode. I considered forcingNonZeroU*::add
to panic in release mode by deferring the check tou*::checked_add
, but this is less explicit for the user than directly usingNonZeroU*::checked_add
.Following @Lokathor's advice on zulip, I have dropped the idea.
@poliorcetics on Discord also suggested implementing
_sub
operations, but I'd postpone this to another PR if there is a need for it. My opinion is that it could be useful in some cases, but that it makes less sense because non-null natural numbers are not stable by subtraction even in theory, while the overflowing problem is just about technical implementation.One thing I don't like is that the type of the
other
arg differs in every implementation:_add
methods accept any raw positive integer,_mul
methods only accept non-zero values otherwise the invariant is also broken, and_pow
only seems to acceptu32
for a reason I ignore but that seems consistent throughoutstd
. Maybe there is a better way to harmonize this?This is it, Iope I haven't forgotten anything and I'll be happy to read your feedback.