Why isn’t there an `impl Add<i64> for u64` when `checked_add_signed` exists?

Although due to the lack of #[cfg(overflow_checks)] it would need a compiler intrinsic (I believe).

At least in part because it would break inference.

x + 0 works today because there's only one option.

If you add impl Add<i8> for u8, then x + 0 will end up hitting i32 fallback for the 0, and thus it'll be u8 + i32, and not exist.

(It's also possible that people intentionally don't want the mixing, and prefer seeing that the types are different.)


Although I would like to take this opportunity to say that I strongly support an overflow_checks cfg for custom numeric types.

Add isn't guaranteed to check, so existence of the checked method is not really helping.

Of course the behavior wouldn't be worse than Sub<u64>, but implicit numeric type conversions are a bit of a taboo topic for Rust. There are a lot of users here burned by C's reckless behavior who will not want to hear about any proposal even slightly in that direction.

  1. There isn’t a method version of panicking addition either—what I was saying is that implementing Add<i64> for u64 would be possible given that checked_add_signed exists.

  2. I’m not saying anything about implicit type conversion—if impl Add<i64> for u64 existed it wouldn’t be an implicit type conversion.

Is this what you had in mind then?

impl Add<i64> for u64 {
    type Output = Option<u64>;
    fn add(self, other: i64) -> Self::Output {

And is there a benefit besides typing less? Some drawbacks are

  • less visibly obvious / principle of least suprise
  • still breaks inference like @scottmcm said; so much code would break that nothing like this will land unless the inference algorithm itself changes

No. What I was saying would be impossible to implement currently without a compiler intrinsic or #[cfg(overflow_checks)]. With that, it’d go like this:

impl Add<i64> for u64 {
    type Output = u64;
    fn add(self, other: i64) -> u64 {
        self.checked_add_signed(other).expect("attempt to add with overflow")
    fn add(self, other: i64) -> u64 {

This is perfectly analogous to other addition implementations.

In that case it's effectively an implicit conversion when it doesn't panic and the cultural pushback will still happen, even if the inference story changes.

1 Like

…it’s an implicit conversion with a change to how overflow is detected, though. But yes, the inference is a blocker.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.