Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upTracking issue for platform-dependent-API TryFrom impls involving usize/isize #49415
Comments
SimonSapin
added
T-libs
C-tracking-issue
labels
Mar 27, 2018
This comment has been minimized.
This comment has been minimized.
|
More discussion on this is also in #48593. |
This was referenced Mar 28, 2018
This comment has been minimized.
This comment has been minimized.
SimonSapin
referenced this issue
Mar 28, 2018
Merged
Stabilize TryFrom / TryInto, and tweak impls for integers #49305
This comment has been minimized.
This comment has been minimized.
|
Not having these impls at all is a "hole" in the functionality of this trait: #49305 (comment) |
regexident
added a commit
to regexident/fpa
that referenced
this issue
Mar 28, 2018
This comment has been minimized.
This comment has been minimized.
Kixunil
commented
Mar 29, 2018
|
An idea: impl TryFrom<u64> for usize {
type Error = SizeConversionError<u64>;
// fn try_from ...
}
impl<T> From<SizeConverstionError<T>> for TryFromIntError {
// fn from ...
}
// Mark use of this trait with portability lint
// The philosophy is similar to e.g. AsRawFd trait
trait SizeConversionExt {
type Value;
fn conversion_never_fails(self) -> Self::Value;
}
// pseudo attribute - don't know the real one
#[cfg(pointer_size = 64)]
impl SizeConversionExt for Result<u64, SizeConverstionError<u64>> {
type Value = u64;
fn conversion_never_fails(self) -> Self::Value {
match self {
Ok(val) => val,
Err(e) => e.uninhabited,
}
}
}
// Portable code:
fn portable<T: TryInto<usize>>(val: T) {
match val.try_into() {
// ...
}
}
// For X86-64
fn non_portable(val: u64) {
#[allow(non-portable)]
use /*something::something*/SizeConversionExt;
let val: usize = val.try_into().conversion_never_fails();
// Do whatever with val
} |
This comment has been minimized.
This comment has been minimized.
|
I think that making all of these conversions go through |
This comment has been minimized.
This comment has been minimized.
|
@clarcharr I’m not sure what you mean. Note that though a generic impl, any I also don’t know what you mean by performance: whatever the error type, with sufficiently advanced inlining the optimizer can see that a given impl only ever returns |
This comment has been minimized.
This comment has been minimized.
|
Bitter experience over many years of porting code that performs integer conversions suggests to me that people will use infallible conversions on code that will later be run on platforms where the conversion does indeed fail, creating a portability headache. Even in the presence of a lint, this stuff often leaches deeply into the design of a program, including things which a lint won't pick up, where it can become extremely difficult to unpick. As @SimonSapin says, with sufficiently good optimisations -- which, IIRC the last time I looked at this is already the case -- both the |
This comment has been minimized.
This comment has been minimized.
Kixunil
commented
Apr 4, 2018
|
I agree with @ltratt. I've recently participated on porting some code from 32 to 64 bit and it wasn't fun. That being said, performance is fine in simple cases, but I guess it would get worse with more complex code where errors are propagated and handled by the caller. That's why I'd prefer what I wrote above: have a special error type with a private field of type |
This comment has been minimized.
This comment has been minimized.
kevincox
commented
Apr 7, 2018
|
Is there any evidence of a performance degradation for having Just to be clear. I'm in favour of having all |
This comment has been minimized.
This comment has been minimized.
|
This issue is not at all about performance. It’s about choosing (or not) to have APIs vary across targets. |
This comment has been minimized.
This comment has been minimized.
kevincox
commented
Apr 7, 2018
|
I must have missed some argument. What is the downside with having |
This comment has been minimized.
This comment has been minimized.
|
@kevincox I personally think that’s what we should do anyway, but as explained in “Background” of the original message of this thread it prevents having non-portable portability-lint-gated |
This comment has been minimized.
This comment has been minimized.
kevincox
commented
Apr 8, 2018
|
Thanks for explaining. One solution would be https://github.com/rust-lang/rfcs/blob/master/text/1210-impl-specialization.md. I believe this would allow the blanket However until then (or if that never comes to fruition) I think I would still prefer having the |
This comment has been minimized.
This comment has been minimized.
|
The
|
This comment has been minimized.
This comment has been minimized.
|
Has there been any progress towards making a decision on this? Selfishly, I would like not to be stuck using a nightly from March (because the removed |
This comment has been minimized.
This comment has been minimized.
tobz1000
commented
May 8, 2018
•
|
I would like this to be finalised too. To me it seems that first option (use |
tobz1000
added a commit
to tobz1000/mines-rs
that referenced
this issue
May 9, 2018
This comment has been minimized.
This comment has been minimized.
|
Prior to #49305 the error types for |
This comment has been minimized.
This comment has been minimized.
Kixunil
commented
May 9, 2018
|
I would prefer the error type to carry information about from which integer the conversion was attempted as without it compiler optimizations will be probably impossible without whole-program analysis. That being said, I prefer cross-platform solution. (Note: AVR has 16 bit addressing.) |
This comment has been minimized.
This comment has been minimized.
|
Wouldn't it be possible to make these all implement |
This comment has been minimized.
This comment has been minimized.
|
@Kixunil Do you mean a single error type that would contain some kind of enum? What would you do with that info? What would be the public APIs? Or if you mean separate error types, that’s potentially a lot of types for all combinations of “infallible if usize is at {least,most} {16,32,64,128} bits”. @clarcharr Is it meaningful for a type to be unstable if stable APIs can still produce a value of that type? |
This comment has been minimized.
This comment has been minimized.
|
@SimonSapin The only way to produce that type would be from It is a sort of hack, but it would allow us to at least add |
This comment has been minimized.
This comment has been minimized.
|
By produce a value of that type I meant something like |
This comment has been minimized.
This comment has been minimized.
Kixunil
commented
May 10, 2018
|
To provide more context about my idea, I wrote a proof-of-concept. |
This comment has been minimized.
This comment has been minimized.
|
@Kixunil This would probably needs two type parameters to support conversions in both directions. But more importantly, |
This comment has been minimized.
This comment has been minimized.
Kixunil
commented
May 20, 2018
•
|
@SimonSapin Good point. Hypothetically, if compatibility lint was easier to implement on methods, it could still be helpful. The associated type could be hidden by sealing the trait. Anyway, I prefer compatibility-first approach. Edit: I just realized, we don't need that trait at all. We could just conditionally compile |
This comment has been minimized.
This comment has been minimized.
|
@Kixunil I only vaguely guess what you mean by sealing the trait, but I believe this also doesn’t solve the problem. |
This comment has been minimized.
This comment has been minimized.
Kixunil
commented
May 26, 2018
|
@SimonSapin similar to what |
SimonSapin
added a commit
to SimonSapin/rust
that referenced
this issue
Jun 6, 2018
This comment has been minimized.
This comment has been minimized.
snim2
commented
Jun 11, 2018
|
@SimonSapin Hi Simon, thanks for pushing this forward. Unfortunately I'm really blocked on this issue (in particular it's the |
This comment has been minimized.
This comment has been minimized.
|
Unfortunately, |
This comment has been minimized.
This comment has been minimized.
snim2
commented
Jun 11, 2018
|
Ok, many thanks. I just noticed that you have a revert commit for this, is that likely to be merged into master? |
This comment has been minimized.
This comment has been minimized.
|
This would be my preferred outcome. I’m gonna talk to people this week about what’s going on with the portability lint and what to do process-wise. |
This comment has been minimized.
This comment has been minimized.
snim2
commented
Jun 11, 2018
|
Many thanks. |
This comment has been minimized.
This comment has been minimized.
|
PR #51564 restores |
SimonSapin commentedMar 27, 2018
Background
For converting between different primitive integer types we have impls of the
Fromtrait (and so ofTryFrom<Error=!>through the genericimpl<T, U> TryFrom<T> for U where U: From<T>) for conversions that always succeed (for exampleu8tou32), andTryFrom<Error=TryFromIntError>for other conversions (for exampleu32tou8, which returnErr(_)on values that would overflow).When
usizeorisizeis involved however, some conversions can be fallible or infallible depending on the target platform’s pointer width. (For exampleu64tousizeon 64-bit v.s. 32-bit platforms.)There is desire to make such impls infallible with
Fromwhenever possible. Since APIs would be different on the target platform, their usage should be gated on a portability lint that is not implemented yet. (The lint would additionally need to be able to "see" that a non-portable impl is used indirectly through a generic impl likeimpl<T, U> TryFrom<T> for U where U: From<T>orimpl<T, U> Into<U> for T where U: From<T>.)A downside of this is that even code that would be portable because it doesn’t care about the error type (because it only tests for the presence of an error, or works in both case though e.g. the
Fromconversion inside the?operator) would still need top opt into "non-portability" in order to silence the lint.In order to be able to stabilize the
TryFromtrait without waiting for the portability lint to be implemented, #49305 removed the affected impls. They are those markedNPin the table in #49305 (comment):TryFrom<usize>foru16,u32,u64,u128,i32,i64,i128TryFrom<isize>fori16,i32,i64,i128TryFrom<_> for usize:u32,u64,u128TryFrom<_> for isize:u16,u32,u64,u128,i32,i64,i128Alternatives
We want to have these impls eventually, but need to chose between:
TryFrom<Error=TryFromIntError>on all platforms.