For conversion between numeric types the current policy is that From
must never fail, for any platform, not just on the target platform. It’s a nice idea, and I think it’s beneficial for portability between 32-bit and 64-bit platforms.
However, I think it goes too far in requiring support for 16-bit and hypothetical 128-bit platforms as well, because this has a cost of promoting dangerous use of as
for conversions that are common on 32-bit and 64-bit platforms.
IMHO the policy doesn’t help portability, because as
does not avoid the problem Into
was meant to avoid, it only hides these types of bugs from the compiler. I find as
to be C-like dangerous, and I would prefer to never use as
in my code.
It causes broken code on 16-bit
For example, if I’m not allowed to use u32.into() usize
, then I’ll have to use u32 as usize
instead, even if I require conversion to never truncate. Lack of this into()
implementation does not make my code work on 16-bit platforms. It makes Rust compile code designed with invalid assumptions without a warning.
I think errors about missing .into()
implementations would help supporting 16-bit platforms — they’d prevent broken programs from running and corrupting data, and make the compiler point out places where the code needs to be fixed first.
Prevents libraries from changing exposed types
The same risk that applies for conversions between usize
on various platforms, also applies to conversions between program’s types and libraries’ types.
I may be forced to use as
casts that are not truncating in the current version of a library, but when the library changes sizes of its types, the as
cast will continue to compile, but it’ll start silently corrupting data. When the library is an FFI, it becomes a safety problem.
OTOH if I could use .into()
everywhere, then such incompatible change would be caught by the compiler (and only if my usage was actually incompatible).
I’m forced to support a platform that doesn’t even exist
Lack of conversion from usize
to u64
causes problems for me on real platforms today. I’m unhappy about having to use as
that is currently dangerous and not future-proof, only because .into()
is meant to seamlessly support hypothetical future platform.
I prefer to fix compile errors when porting code to a new platform, than have to use dangerous (and non-portable) casts on platforms that I currently use.
Proposal
- Add conversion from
usize
tou64
on all current platforms. Leave it unimplemented on a future 128-bit platform. - Add conversion from
u32
tousize
on 32-bit and wider platforms. Leave it unimplemented on 16-bit platforms.
This is limited and keeps the current requirement that code must compile on both 32-bit and 64-bit platforms.
Alternative
Discussion Pre-RFC: a vision for platform/architecture/configuration-specific APIs mentions “compatibility targets”.
- Implement all conversions that are lossless for all compatibility targets (and don’t restrict conversions because they’re lossy on platforms that aren’t the targets).