0

Basically, I want to implement pipeline-operator (binary operator for function application) on Box<T> using Operator overloading in Rust.

I understand Box<T> is a structure

https://doc.rust-lang.org/src/alloc/boxed.rs.html#175-178

and the below is the code I found here for struct Wrapped<T>(T) that has the pipeline-operator as Shr >>.

https://stackoverflow.com/a/17111630

use std::ops::Shr;

struct Wrapped<T>(T);

impl<A, B, F> Shr<F> for Wrapped<A>
where
    F: FnOnce(A) -> B,
{
    type Output = Wrapped<B>;

    fn shr(self, f: F) -> Wrapped<B> {
        Wrapped(f(self.0))
    }
}

fn main() {
    let string = Wrapped(1) >> (|x| x + 1) >> (|x| 2 * x) >> (|x: i32| x.to_string());
    println!("{}", string.0);
}
// prints `4`

Here I want Box<T> instead of Wrapped<T> for the pipeline-operator.

I also found a code here to overload Add::add for Vector

https://stackoverflow.com/a/28005283

impl<'a, 'b> Add<&'b Vector> for &'a Vector {
    type Output = Vector;

    fn add(self, other: &'b Vector) -> Vector {
        Vector {
            x: self.x + other.x,
            y: self.y + other.y,
        }
    }
}

Therefore, I suppose there must be a way to implement pipeline-operator (binary operator for function application) on Box<T>.

So far, I did

use std::ops::Shr;

impl<A, B, F> Shr<F> for Box<A>
where
    F: FnOnce(A) -> B,
{
    type Output = Box<B>;

    fn shr(self, f: F) -> Box<B> {
        Box::new(f(&self))
    }
}

etc. but the code doesn't work.

error[E0210]: type parameter `A` must be used as the type parameter for some local type (e.g., `MyStruct<A>`)
 --> src/main.rs:6:10
  |
6 |     impl<A, B, F> Shr<F> for Box<A>
  |          ^ type parameter `A` must be used as the type parameter for some local type
  |
  = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
  = note: only traits defined in the current crate can be implemented for a type parameter

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=5eb74e35e2b5c23b0ab9ba020f1a7b54

Can you fix the code? Thanks.

Chayim Friedman
  • 47,971
  • 5
  • 48
  • 77
KenSmooth
  • 275
  • 1
  • 10
  • 4
    You are trying to implement a foreign trait (`Shr`) for a foreign type (`Box`), which is not allowed in Rust. The reason is that in another module, you could write a similar implementation of `Shr` for `Box` that behaves differently; then, if you imported both modules into a new project, the compiler wouldn't know which implementation to use. – Coder-256 Jan 20 '22 at 05:36
  • 1
    I'm not sure this is a duplicate, but see [How do I implement a trait I don't own for a type I don't own?](https://stackoverflow.com/questions/25413201/how-do-i-implement-a-trait-i-dont-own-for-a-type-i-dont-own). Generally, like @Coder-256 said, it's impossible. This is called _coherence_, or _the orphan rule_. – Chayim Friedman Jan 20 '22 at 05:40
  • At the moment, it is not possible to implement a pipe operator in Rust for arbitrary types. You could maybe use a macro, but it seems strictly more difficult/complicated than a wrapper; the wrapper you have in your question is slightly inconvenient, but honestly it's probably the best and simplest solution. – Coder-256 Jan 20 '22 at 05:44
  • @Coder-256 "At the moment"? Are there any RFCs, or even suggestions, to disable coherence? – Chayim Friedman Jan 20 '22 at 05:45
  • [See here](https://users.rust-lang.org/t/pipe-results-like-elixir/11175/18) for past discussion specifically about the pipe operator. As for coherence and the orphan rules: everybody hates them, and also everybody hates Rust's aliasing/borrowing rules, and so on and so forth... the point is, you pick Rust if you really care about doing things the *right* way, not the easy way. The rules are annoying but they exist for a reason. Generally, any programming language has to pick 2 out of 3: fast, safe, and easy. Rust picks the first 2. – Coder-256 Jan 20 '22 at 05:52
  • Thanks Coder-256 and Chayim Friedman, the fact sounds disappointing but informative.. – KenSmooth Jan 20 '22 at 06:02
  • 2
    It's *good* that this isn't allowed. What would right shift on `Box` even mean? New semantics go into new types. Then you can define shifting in a context where it makes sense. – GManNickG Jan 20 '22 at 06:43

0 Answers0