-
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
Allow comparisons between integers of different types #2021
Closed
Closed
Changes from 5 commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
f5e9a15
template copied
VFLashM 31d92e4
all but motivation added
VFLashM 605f3e8
better motivation
VFLashM d4fd71c
grammar fix
VFLashM cccd48e
rfc file moved into right dir
VFLashM 54bef7d
signed->unsigned typo fixed, Ord/Eq mentioned as optional, unresolved…
VFLashM ca6b574
widening to signed added as a more efficient way to compare signed/un…
VFLashM c6af879
added note about branching into implementation, explicit branching re…
VFLashM d2612f5
how we teach section updated, short description of potential changes
VFLashM File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
- Feature Name: heterogeneous_comparisons | ||
- Start Date: 2017-06-06 | ||
- RFC PR: (leave this empty) | ||
- Rust Issue: (leave this empty) | ||
|
||
# Summary | ||
[summary]: #summary | ||
|
||
Allow to compare integer values of different signedness and size. | ||
|
||
# Motivation | ||
[motivation]: #motivation | ||
|
||
Right now every comparison between different integral types requires a cast. These casts don't only clutter the code, but also encourage writing incorrect code. | ||
|
||
The easiest way to compare signed and unsigned values is to cast unsigned value to signed type. It works most of the time, but it will silently ignore overflows. | ||
|
||
Comparison between values of different integer types is always well-defined. There is only one correct result and only one way to get it. Allowing compiler to perform these comparisons will reduce both code clutter and count of hidden overflow/underflow errors users make. | ||
|
||
# Detailed design | ||
[design]: #detailed-design | ||
|
||
`Ord` and `Eq` traits should be modified to allow `Rhs` type not equal to `Self`. | ||
|
||
After that `PartialEq`, `Eq`, `PartialOrd` and `Ord` should be implemented for all pairs of signed/unsigend 8/16/32/64/(128) bit integers and `isize`/`usize` variants. | ||
|
||
Implementation for signed-singed and unsigned-unsigned pairs should promote values to larger type first, then perform comparison. | ||
|
||
Implementation for signed-unsigned pairs should first check if signed value less than zero. If not, then it should promote both values to signed type with the same size as larger argument type and perform comparison. | ||
|
||
# How We Teach This | ||
[how-we-teach-this]: #how-we-teach-this | ||
|
||
No changes I can find or think of. | ||
|
||
# Drawbacks | ||
[drawbacks]: #drawbacks | ||
|
||
* It might break some code relying on return type polymorphism. It won't be possible to infer type of the second argument from type of the first one for `Eq` and `Ord`. | ||
* Correct signed-unsigned comparison requires one more operation than regular comparison. Proposed change hides this performance cost. If user doesn't care about correctness in his particular use case, then cast and comparison is faster. | ||
* The rest of rust math prohibits mixing different types and requires explicit casts. Allowing heterogeneous comparisons (and only comparisons) makes rust math somewhat inconsistent. | ||
|
||
# Alternatives | ||
[alternatives]: #alternatives | ||
|
||
* Keep things as is. | ||
* Add generic helper function for cross-type comparisons. | ||
|
||
# Unresolved questions | ||
[unresolved]: #unresolved-questions | ||
|
||
Is `Ord` between float and int values as bad idea as it seems? |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
I think that promotion should be to the "unsigned" type since an unsigned type can hold values larger than a signed type of the same size.
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.
+1
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.
Both signed and unsigned types can hold values other type cannot.
You either have to check that signed value is non-negative then cast to unsigned, or have to check that unsigned value is not greater than maximum value of signed type.
Example:
I personally find check for non-negativeness a bit cleaner.
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.
You mean
std::i32::MAX as u32
?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.
It's also less prone to the typo of checking whether a
u32
is greater thanstd::u32::MAX
rather thanstd::i32::MAX
.EDIT: ...and I just realized that's what @eddyb meant by his comment.
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.
@VFLashM You have a typo in the RFC. It says "promote both values to signed type", which actually overflows for
b > std::i32::MAX
.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.
Oh, darn. Your're right. That's a typo in RFC. I absolutely meant promotion to unsigned.
Thanks.
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.
@VFLashM
The RFC says:
Your first code snippet says:
I think this is all that @TimNN was saying: after checking for less-than-zero, the
as
afterwards should be to the unsigned type, not the signed type as the RFC currently says.EDIT: the previous two comments hadn't appeared when I wrote this :)