Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rust Shr Operator

Tags:

rust

I'm trying to overload the right shift operator (>>) in rust to implement a Maybe bind.

enum Maybe<T> {
    Nothing,
    Just(T)
}

/// Maybe bind. For example:
///
/// ```
/// Just(1) >> |x| Just(1 + x) >> |x| Just(x * 2)
/// ```
impl<'a, T, U> Shr<|&T|: 'a -> Maybe<U>, Maybe<U>> for Maybe<T> {
    fn shr(&self, f: &|&T| -> Maybe<U>) -> Maybe<U> {
        match *self {
            Nothing => Nothing,
            Just(ref x) => (*f)(x)
        }
    }
}

fn main() {}

However, I'm running into an error trying to invoke the closure:

<anon>:15:28: 15:32 error: closure invocation in a `&` reference
<anon>:15             Just(ref x) => (*f)(x)
                                     ^~~~
error: aborting due to previous error
playpen: application terminated with error code 101
Program ended.

Why is it erroneous to invoke a borrowed closure, and how can I resolve the issue and implement the bind?

I found a similar question on stackoverflow, but rust has changed enough since then so that it no longer works.

like image 560
mwhittaker Avatar asked Jul 02 '14 03:07

mwhittaker


2 Answers

Overloading the shift-right operator is not a good idea here because of various limitations it imposes on you. It takes everything by reference, whereas what you want is to take everything by value.

It is not possible to call a closure through an immutable reference; you must have a mutable reference to call it, because it may mutate its environment.

The solution in the time of the question you referred to was to use &fn(&A) -> B, which was an immutable closure; at present we do not have that type; |&A| -> B is parallel to &mut fn(&A) -> B from that time, which simply can’t work because it is being done through an immutable reference. The sensible thing, of course, is to take self by value and have the function as |A| -> B; this is what Option.and_then, which is exactly what you are trying to implement, does.

In short, what you are trying to do is currently impossible, though it might become possible again at some point in the future. Use a regular method instead of trying to overload the operator.

Or just use Option, already there:

Some(1i).and_then(|x| Some(1 + x))
        .and_then(|x| Some(x * 2))
like image 128
Chris Morgan Avatar answered Nov 09 '22 19:11

Chris Morgan


This is possible nowadays. Shr takes by value, and there are unboxed closures:

use std::ops::Shr;
use Maybe::{Nothing,Just};

#[derive(Debug)]
enum Maybe<T> {
    Nothing,
    Just(T)
}

impl<T, U, F> Shr<F> for Maybe<T>
    where F: FnOnce(T) -> Maybe<U>
{
    type Output = Maybe<U>;

    fn shr(self, f: F) -> Maybe<U> {
        match self {
            Nothing => Nothing,
            Just(x) => f(x)
        }
    }
}

fn main() {
    let a = Just(1u8);
    let b = a >> |v: u8| Just(v + 1);
    println!("{:?}", b)
}
like image 30
Shepmaster Avatar answered Nov 09 '22 19:11

Shepmaster