Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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;
    }
}
like image 679
nyarlathotep108 Avatar asked Sep 04 '20 12:09

nyarlathotep108


People also ask

Can you overload an operator twice?

No this is not possible. The compiler can't know which version you want, it deducts it from the parameters. You can overload many times, but not by the return type.

Which operators can be overloaded in Rust?

Only operators backed by traits can be overloaded. For example, the addition operator ( + ) can be overloaded through the Add trait, but since the assignment operator ( = ) has no backing trait, there is no way of overloading its semantics.

Can you overload all operators?

Can we overload all operators? Almost all operators can be overloaded except a few.

Can you overload methods in Rust?

Rust allows for a limited form of operator overloading. There are certain operators that are able to be overloaded. To support a particular operator between types, there's a specific trait that you can implement, which then overloads the operator.

Is it possible to implement operator overloading in rust like C++?

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?

What is rust by example?

Operator Overloading - Rust By Example Rust by Example (RBE) is a collection of runnable examples that illustrate various Rust concepts and standard libraries. Introduction 1. Hello World 1.1. Comments 1.2. Formatted print 1.2.1. Debug 1.2.2. Display 1.2.2.1. Testcase: List 1.2.3. Formatting 2. Primitives 2.1. Literals and operators 2.2. Tuples

What is the most unstable feature in rust?

impl_trait_in_bindings — The key to our “true” function overloading, so far the most unstable feature, may cause the compiler to crash. I am using my functionate macro here but by the time you read this I might’ve added a feature to automatically create semi-overloaded-functions to it That’s a weird Rust piece of code.


2 Answers

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.

like image 92
Matthieu M. Avatar answered Oct 16 '22 23:10

Matthieu M.


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.

like image 4
Netwave Avatar answered Oct 17 '22 00:10

Netwave