nyarlathotep108
nyarlathotep108

Reputation: 5523

More than one operator overload in Rust

I know it is possible by using traits to implement operator overloading in Rust. In C++ is also possible to have multiple operator overloading for the same operator and the same struct, and switch on/off which operator to use.

Is it possible to do the same as the following C++ code in Rust? Possibly in the same source file?

struct S
{
    int value;
};

namespace first
{
S operator+(S lhs, S rhs)
{
    return S{ lhs.value + rhs.value };
}
}

namespace second
{
S operator+(S lhs, S rhs)
{
    return S{ lhs.value * rhs.value };
}
}

int main()
{
    S s1{5};
    S s2{10};
    {
        using namespace first;
        S s3 = s1 + s2;
        std::cout << s3.value << std::endl;
    }
    {
        using namespace second;
        S s3 = s1 + s2;
        std::cout << s3.value << std::endl;
    }
}

Upvotes: 7

Views: 1822

Answers (2)

Matthieu M.
Matthieu M.

Reputation: 299790

The idiomatic answer in Rust to:

How do I use different overloads of +, <, ... for my Type?

is to wrap the type up and implement the operator on the wrapper.

Example on the playground

#[derive(Clone, Copy, Debug)]
struct S(i32);

#[derive(Debug)]
struct Adder(pub S);

impl std::ops::Add<S> for Adder {
    type Output = S;

    fn add(self, other: S) -> S { S(self.0.0 + other.0) }
}

impl std::ops::Add<Adder> for S {
    type Output = S;

    fn add(self, other: Adder) -> S { S(self.0 + other.0.0) }
}

#[derive(Debug)]
struct Multiplier(pub S);

impl std::ops::Add<S> for Multiplier {
    type Output = S;

    fn add(self, other: S) -> S { S(self.0.0 * other.0) }
}

impl std::ops::Add<Multiplier> for S {
    type Output = S;

    fn add(self, other: Multiplier) -> S { S(self.0 * other.0.0) }
}

fn main() {
    let one = S(5);
    let two = S(10);

    println!("{:?}", one + Adder(two));
    println!("{:?}", Adder(one) + two);
    
    println!("{:?}", one + Multiplier(two));
    println!("{:?}", Multiplier(one) + two);
}

This idiom can be seen in the standard library where the std::num::Wrapping type can be used to wrap an integer in which case addition, subtraction, and multiplication are re-defined to use modulo arithmetic.

Upvotes: 7

Netwave
Netwave

Reputation: 42678

Is it possible to do the same as the following C++ code in Rust? Possibly in the same source file?

No, it is not (not exactly) for the following reasons:

  1. A struct cannot implement the same trait twice (why would you want that?)
  2. There is no function overloading in rust

Regarding what you want in your code, you can approximate it like this:


#[derive(Debug)]
struct S(i32);

mod first {
    use crate::S;
    pub trait Foo {
        fn bar(self, s: S) -> S;
    }
    
    impl Foo for S  {
        fn bar(self, s: S) -> S {
            S(self.0 + s.0)
        }
    }
}

mod second {
    use crate::S;
    pub trait Foo {
        fn bar(self, s: S) -> S;
    }
    
    impl Foo for S  {
        fn bar(self, s: S) -> S {
            S(self.0 * s.0)
        }
    }
}

fn main() {
    let first_res = first::Foo::bar(S(1), S(2));
    let second_res = second::Foo::bar(S(1), S(2));

    println!("{:?}, {:?}", first_res, second_res);
    
    {
        use first::Foo;
        println!("{:?}", S(1).bar(S(2)));
    }
    
    {
        use second::Foo;
        println!("{:?}", S(1).bar(S(2)));
    }
}

Playground

Notice that the Foo traits are indeed different traits for the compiler. So you are implementing two different traits, not one. For the same reason, both bar methods are different ones too.

Upvotes: 4

Related Questions