I feel that implicit widening should be added to Rust. Unlike integer overflows and narrowing conversions, widening conversions can never change the mathematical value of a variable. As such, they are widely recognized as safe and are implemented by widely used languages including C, C++, Java, and C#. Not only that, but the commonly used gcc and clang compilers do not even have options to warn about widening conversions, despite the presence of hundreds of optional warnings including ones for narrowing conversions. Think about what that says about widening conversions. Keep in mind that both these compilers are open source and frequently have new warnings contributed.
The lack of widening conversions makes some logic which is trivial to implement in common languages complex to implement in Rust. A particularly egregious class of examples involves comparing a usize to some fixed-width integer, such as u32 or u64. In such scenarios, it is unknown which of the two types is larger than the other. In C this is of no consequence because the smaller type will be implicitly widened to the larger type. But in Rust the programmer has to carefully write the code to handle both cases. Here are a couple examples:
Check if twice the value of a u64 fits into a usize. In C:
return x <= SIZE_MAX / 2;
In Rust:
x as usize as u64 == x && x as usize <= usize::max_value() / 2
Or, check if a usize value is less than a u32 constant. In C:
return x < LIMIT;
In Rust:
if x as u32 as usize == x {
// Compare as u32 (for usize smaller than u32)
(x as u32) < LIMIT
} else {
// Compare as usize (for usize larger than u32)
x < LIMIT as usize
}
As you can see, the Rust examples are far more complicated and error-prone. It should not be that way. Note that this type of limit checking is often used in security-sensitive code.
(Of course, if someone can provide simpler Rust code that is guaranteed to work on all Rust implementations, then please go ahead. Keep in mind that the size of a usize is machine-dependent.)
There have been a number of objections raised to implicit widening which I feel are misguided. These can be briefly summarized and rebuted as follows:
1.) āThe problem should be solved by polymorphic indexing instead.ā Actually, polymorphic indexing only solves a subset of the problems. The examples I gave above had nothing to do with indexing.
2.) āInteger conversions in C are confusing and unsafe.ā While this premise is already questionable, it really only applies to ālossyā conversions where the mathematical value changes as a result of the conversion. I am only suggesting lossless, āwideningā conversions.
3.) āImplicit widening conversions can āhideā integer overflow bugs.ā While this is arguably true in some cases, such bugs are actually caused by integer overflows, not by widening conversions. As such, these bugs can and do occur regardless of implicit widening conversions. Other means such as static analysis and runtime checking are vastly more useful for detecting integer overflow bugs. Helpfully, the latter has already been implemented in Rust; see this RFC: https://github.com/rust-lang/rfcs/blob/master/text/0560-integer-overflow.md.
4.) āFor explicitness and type safety, it should be required to explicitly cast between integer types, just like any other type.ā Actually, when working with integer types of unknown size, such as Rustās usize, it may be impossible to know ahead of time which of the two types to cast to without making assumptions about the implementation. In addition, the fact that two variables might have different integer types is of no consequence when performing mathematical operations such as comparisons unless there is possibility of the mathematical result changing as a result of a type conversion. Only in that case is correctness is in question and it is reasonable to require an explicit cast. Finally, requiring explicit casts for widening conversions introduces more use of the āasā operator which can also perform narrowing conversions with the exact same syntax, thereby making to harder to find casts which actually result in changes to mathematical results.
In summary, I think it is clear that implicit widening conversions would increase the usability of Rust and make it easier to write correct programs.
I posted to this thread as this was the only substantive discussion on the topic I could find. If anyone happens to know of a better place to post, then please let me know. I am aware I could post a full RFC and pull request, but Iām not sure I have time for that right now.