Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Idiomatic way to add a u8 to i8

Tags:

rust

Consider the following code:

let mut val : u8 = 125;
let deltas : [i8; 4] = [5, -5, 5, 5];

let delta = select_current_delta(deltas);

val += delta;

This seems simple. I want to either increase or decrease a byte value based on some criteria (and I have a way to prevent overflow of a u8 value).

This, of course, does not compile:

 > rustc lala.rs
 lala.rs:7:12: 7:17 error: mismatched types:
  expected `u8`,
     found `i8`
 (expected u8,
     found i8) [E0308]
 lala.rs:7     val += delta;
                      ^~~~~

Duh! Mixing signed and unsigned types seems to be forbidden in Rust. How about this?

val = (val as i8 + delta) as u8;

This compiles, but when I try to run it...

> ./lala
thread '<main>' panicked at 'arithmetic operation overflowed', lala.rs:7

Yeah, i8's max value is 125, adding 5 will overflow, even though the value is perfectly fine for u8.

I was able come up with two solutions that work:

val = (val as i16 + delta as i16) as u8;
// or
if delta < 0 { val -= (-delta) as u8 }
else { val += delta as u8}

Neither of those seem elegant to me. Is there an idiomatic way to add a u8 to a i8?

like image 839
Tomo Avatar asked Aug 20 '15 06:08

Tomo


1 Answers

Is there an idiomatic way to add a u8 to a i8?

The problem of adding a u8 to a i8 (with +) is: what type should the result be? Neither u8 or i8 is better, and using i16 while correct would probably be surprising.

Thus, for now, mixed-integrals operands are not supported. The idiomatic way is to cast both operands to a common type, which will also be the type of the result. This is already what you are doing.

But, what of u8 += i8 ?

Unfortunately, at the moment, this is sugar for u8 = u8 + i8 and therefore has all the limitations of + even though the result type would not be an issue.

As all annoying limitations of Rust, there's a RFC for it! This is PR #953: Overloaded Assignment Operations. This RFC is in final comment period so a decision is expected soon, and hopefully this means that it will be accepted and Rust will gain support for mixed-integrals assignment operations.


As a personal preference, for now, I would go for:

val = (val as i16 + delta as i16) as u8;

which avoids the branch.

like image 97
Matthieu M. Avatar answered Sep 28 '22 04:09

Matthieu M.