Feature: `Then` trait for easy method chaining

This trait would, besides being convenient for avoiding methods nesting, prevent common occurrences of Error[0499]: cannot borrow * more than once.

This trait would look something similar to this

pub trait Then{
    fn then<Out, F: FnOnce(Self) -> Out>(self, operator: F) -> Out
    where Self: Sized
    {
        operator(self)
    }
}

and would be default implemented for any generic type T.

If we want to mutably borrow a variable in a nested method while also borrowing it in the surrounding method, this will currently lead to an Error[4099]:

struct Foo();

impl Foo{
    pub fn baz(&mut self, bar: Bar){}
}

struct Bar();

impl Bar{
    pub fn new(foo: &mut Foo) -> Self{
        Bar()
    }
}

fn main() {
    
    let mut foo = Foo();
    
    foo.baz(Bar::new(&mut foo));
}
error[E0499]: cannot borrow `foo` as mutable more than once at a time
  --> src/main.rs:19:22
   |
19 |     foo.foo(Bar::new(&mut foo));
   |     --- ---          ^^^^^^^^ second mutable borrow occurs here
   |     |   |
   |     |   first borrow later used by call
   |     first mutable borrow occurs here

To avoid this, one would need to bind Bar let mut bar = Bar::new(&mut foo) and then call foo.baz(bar) but this trait would allow one to avoid this like so:

Bar::new(&mut foo).then(|bar| foo.baz(bar));
1 Like

There's a crate for that

2 Likes

But is there any dowsnide to including it in the standard library?

Rust prefers to keep the standard library small. If something can be delegated to crates, it usually is.

This is because there's only one version of the standard library, which can't make breaking changes. It adds size overhead to most Rust binaries and libraries.

This trait is relatively small and simple, so not too bad to add, just part of scope creep.

But if it's meant to be built in and not a crate, then a more interesting proposition would be to have a native syntax for it, such as |> operator.

Well that is something I can't really argue as the decision regarding the feature set of the standard lib is not up to me. I know other modern programming languages like Kotlin have that feature and generally any crate you add bares some risks and vulnerabilities. Having this as part of the standard library guarantees, that it's always up-to-date, working correctly with the latest Rust release.

There are a number of users (often in corporate environments) who pin their rustc to an older version intentionally. By using a crate rather than (a hypothetical subset of) std in this scenario, cargo update gives you these guarantees.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.