Why can't u32 add or subtract i32?

550 Views Asked by At
let a: u32 = 10;
let b: i32 = 100;
let c = a - b;

Even this simple operation doesn't work. u32 just can't operate with i32. But I really wonder what's the design principle behind this. I don't think u32 - i32 is more dangerous than u32 - u32. For example:

let a: u32 = 10;
let b: u32 = 100;
let c = a - b;

Does compile, but it panics at runtime. So why is Rust so paranoid about operating between different numeric types? And what's the idiomatic way to handle this, just put as everywhere?

I find it a bit crazy that even checked operations don't work on different numeric types.

let a: u32 = 10;
let b: i32 = 100;
let c = a.checked_sub(b);
1

There are 1 best solutions below

1
Colonel Thirty Two On

This isn't unique to signed versus unsigned; Rust won't even let you add differently sized integers together:

fn main() {
   println!("{}", 5u32 + 10u16);
}
error[E0308]: mismatched types
 --> src/main.rs:3:26
  |
3 |    println!("{}", 5u32 + 10u16);
  |                          ^^^^^ expected `u32`, found `u16`

error[E0277]: cannot add `u16` to `u32`

For the specific case of adding a signed value to an unsigned one, there are functions like checked_add_signed, overflowing_add_signed, saturating_add_signed, and wrapping_add_signed.

Ok, people might disagree on this, but u32.checked_sub(i32) surely should be u32? I really don't think it's so ambiguous.

You acknowledge in your own comment that you don't think everyone will agree on an obvious behavior, and that really is the crux of the issue. C and C++ have some awkward rules regarding integer promotion - a stray unqualified literal like 123 in an expression will convert an expression to a signed integer. Rust decided to make everything explicit.