-
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: Checked integer conversions #1218
Conversation
A few suggestions. First, the bikeshedding ones:
Now, the non-bikeshedding ones:
I have no opinion so far about the |
I feel this RFC is tackling too many things at once, many of which can be done in external crates. I'm all for the |
Floating point is a separate non-trivial problem and I intentionally don't touch it in this RFC, so I don't use
I try to keep direct correspondence between arithmetic and conversion methods. Moreover, something like
Oh, I've missed it. I thought it is now called |
I've used the |
👍 I wholeheartedly agree with the Motivation section and think it's an important problem to solve. Implementation of I like consistency with I don't have an opinion on conversion to pointers. |
I generally support more and better-defined conversion traits, but I'm not convinced that this design (one trait with a bunch of specific-to-numbers methods) is necessarily a good idea. The other day (I only just found out about this RFC from TWiR), I got fed up with the lack of conversion traits and started a crate to try and address this. The current work is at https://github.com/DanielKeep/rust-conv (docs are in the code; no generated docs yet). The first two traits I've implemented are
Also, I've separated the "what to do on overflow/underflow" issue entirely: the result of conversions returns that in the error type (if possible), and there are some helper methods that let you do things like So to map the above to your trait, they're effectively:
Aside from the "implement Either way, I'm glad this is being brought up. Having recently suffered through writing some pathologically generic code that had to deal with value conversions, I'm very much in favour of the situation being improved! :) |
The motivation is that all the introduced operations - overflows, wrapping, saturation - lie in the domain of bounded integer arithmetic. If a type can implement some of these methods, then it can implement others too, so its logical to gather them under one trait. In fact, I think the good way to stabilize the analogous arithmetic operations is to gather them into traits too:
Floating point numbers have sufficiently distinct set of problems - wrapping doesn't exist, overflows / underflows are totally different, saturation is irrelevant (?), a lot of new stuff appears - inexact calculation, rounding modes, infinities / nans - a lot of rust-conv deals specifically with it. Note, that floats currently provide none of that wrapping-checking methods emerged after the adoption of #560. I think integers and floats are sufficiently different entities to not generalize over both of them.
I'll add an alternative to always panic in
Yeah, I'm not sure either. It's there for consistency. If |
I'm wondering whether |
I'm a fan of zero overhead. For example in graphics algorithms it's typical to do calculations on 16 or 32-bit values and save results in u8 pixels. The cast to u8 is not supposed to overflow if the algorithm is implemented correctly, so checks in final builds are not needed, but of course bugs often happen during development. Like with arithmetic overflow in Rust, it's a compromise to have extra checking and also zero overhead in release builds. I like it (I wouldn't object to rename of |
@pornel |
I've made some editorial tweaks to the RFC and renamed |
@petrochenkov Nice RFC, thanks! I am in support of implementing the normal conversion traits and the type parameter for sure -- these are things that only Regarding the new trait, while it seems like a reasonable design, I agree with others that this may be best prototyped out of tree, and perhaps executed in a more general way before landing in At some point we would really like to revamp the rust-lang That said, I'm not strongly against landing such a trait directly in |
cc @wycats @rust-lang/libs |
I'd personally like to see some usage of let foo = bar.cast::<u16>(); Basically put the type parameter on the method call instead of the destination. The trait as-is doesn't currently allow for this (like |
I still have hope, that "upcoming rebase by @nikomatsakis" is just around the corner. Regarding the choice between std and out of tree, I prefer std because I'd like this trait to go through stabilization process synchronously with other wrapping/checking methods. |
The libs team discussed this RFC a bit yesterday, which led to the following:
Would you consider making a PR for the basic conversions, and adjusting this RFC to focus purely on casting? |
Sure |
I haven't mentioned it here, but if we employ D-style parentheses-elision (discussed here) in addition to type ascription, then safe casting will feel like a breeze!
|
@alexcrichton I agree that let foo = u16::cast(bar); Or maybe let foo = u16::cast_from(bar); |
Hm I can see how avoiding I guess if saturating casts are more complication and they're indeed wanted then they can exist, which in some sense motivates all the others as you've got 3/4 methods anyway... |
FWIW, I'm not a big fan of the idea that |
+1 for fewer inherent methods: |
In the standard library wrapping casts are used for hashing/serialization ( |
There are only a few cases like hashing/serialization which do not care about the excessive bits. These wrapping casts can also be done using |
This is exactly what I'd like to avoid.
Personally I'm not aware of any. AFAIK, saturating arithmetic is widely used in few specific domains, but not much outside of them. |
If |
@photino No, since in |
Saturating arithmetic is extremely useful in many cases, since you get the best possible lossy result, by simply saturating the bound. |
As a quick update on this RFC, we talked about it in triage yesterday and the conclusion was that @sfackler and @aturon are going to draft up an RFC for a generic trait to operate with fallible conversions. We believed that if we had such a trait that these methods may be much less motivated. My personal take on the a fallible conversion trait is that I think it'd almost replace the need for these methods altogether. Going over the methods again in the mindset that we've got a fallible conversion trait:
So all in all, once you lose the motivation of Note, however, that this is all pinned on an ergonomic fallible conversion trait (which doesn't exist). Depending on how that plays out we still may want these methods for ergonomics. This is when I at least eagerly await the RFC from @sfackler :) |
Both rust-lang/rust#31825 and rust-lang/rust#31858 are cases of replacing an incorrect |
Wrapping casts could be implemented as |
I would also argue for
Not quite. Depending on the source and target, such as My personal use-case, that lead to rediscovering this RFC via rust-lang/rust#32421, will be satisfied by just I don't really think |
@digama0 Specifically, you can use |
@DanielKeep I agree that that's the right approach for an "everything you ever wanted" conversion library like |
Assuming we add a Example of pub trait CoerceFrom<T>: Sized {
fn coerce_from(from: T) -> Self;
}
impl<A, T: TryFrom<A>> Coerce<T> for A {
fn coerce_from(from: T) -> Self {
match from.try_from() {
Ok(value) => value,
Err(value, error) => {
panic!("Cannot coerce value {} of type {} into type {} because {}", display(value), type_name::<A>(), type_name::<B>(), error)
}
}
}
} It would replace I would add a I would also add @DanielKeep I'd get rid of |
@Zoxc Most of what Just, as an aside, |
I'd avoid using the word "coerce" for this, just to avoid (further) confusion. It already has a specific meaning in Rust's type system, and a specific (different!) meaning in some type-theoretical circles, and this would be a third. (Lord knows we've already had enough confusion between those two, largely out of my own fault.) |
🔔 This RFC is now entering its week-long final comment period 🔔 The libs team discussed this during triage and the conclusion was that with the recently-added |
Ok, the libs team got a chance to discuss this RFC yesterday and the conclusion was that we feel the same where Thanks regardless though for the RFC @petrochenkov! |
Implement several new conversion methods for primitive integer types.
Rendered