Using operator overloading with Type Aliase and/or new Type Idiom

We can create type-aliase as below:

type Kilometers = i32;

let x: i32 = 5;
let y: Kilometers = 5;

println!("x + y = {}", x + y);

and we can create new-type-idiom as below:

struct Kilometers(i32);

But with the new-type-idion, I could not implement operator-overloading, I tried this playground:

use std::ops::Add;

struct Kilometers(i32);

impl Add for i32 {
    fn add(self, other: Kilometers) -> i32 {
        self + other
    }
}

fn main() {
    let x: i32 = 5;
    let y = Kilometers(5);
    println!("x + y = {}", x + y);
}

But got the below error:

   Compiling playground v0.0.1 (/playground)
error[E0119]: conflicting implementations of trait `std::ops::Add` for type `i32`:
 --> src/main.rs:5:1
  |
5 | impl Add for i32 {
  | ^^^^^^^^^^^^^^^^
  |
  = note: conflicting implementation in crate `core`:
          - impl std::ops::Add for i32;

error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
 --> src/main.rs:5:1
  |
5 | impl Add for i32 {
  | ^^^^^^^^^^^^^^^^ impl doesn't use types inside crate
  |
  = note: the impl does not reference any types defined in this crate
  = note: define and implement a trait or new type instead

error: aborting due to 2 previous errors

Some errors occurred: E0117, E0119.
For more information about an error, try `rustc --explain E0117`.
error: Could not compile `playground`.

To learn more, run the command again with --verbose.

Add has a RHS type parameter which defaults to Self. You have to explicitly select it when different, see below.

However, please don’t do it like this. The type safety you gained with a “Kilometers” newtype is lost if you can just add it to an integer and get another untyped integer.

use std::ops::Add;

struct Kilometers(i32);

impl Add<Kilometers> for i32 {
    type Output = i32;
    fn add(self, other: Kilometers) -> i32 {
        self + other.0
    }
}

fn main() {
    let x: i32 = 5;
    let y = Kilometers(5);
    println!("x + y = {}", x + y);
}
1 Like

Type aliases and new types are very different when it comes to trait implementations. The orphan rules disallow implementing a foreign trait for a foreign type. Add is a foreign trait for you (it’s defined outside of your current crate), so the type you implement it on must be yours. A new type (struct X) is considered yours, but a type alias (type X = i32) is just another name for the underlying type (i32), and that type is not defined in your crate. Another reason is that Add is already implemented for i32 (and X is just another name for that type), so you can’t implement it again.

1 Like

Is there a way to create my custom operator like the +

You can’t create custom operators (like using an alternate symbol) in Rust. However, you can overload + for your own types (struct X), like @birkenfeld’s example shows.