Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can I not call FnMut twice in a line?

Taking example snippets from here: the following doesn't compile

fn foobar<F>(mut f: F)
    where F: FnMut(i32) -> i32
{
    println!("{}", f(f(2))); 
    // error: cannot borrow `f` as mutable more than once at a time
}

fn main() {
    foobar(|x| x * 2);
}

but this does

fn foobar<F>(mut f: F)
    where F: FnMut(i32) -> i32
{
    let tmp = f(2);
    println!("{}", f(tmp)); 
}
 
fn main() {
    foobar(|x| x * 2);
}

I don't understand why the first snippet is illegal: it's effectively the same as the second one, just written more concisely. More specifically, why must f(f(2)) mutably borrow f twice? It can simply borrow the inner f to compute the value of f(2), and then borrow the outer f and apply it to the value.

like image 964
nalzok Avatar asked Sep 26 '21 20:09

nalzok


People also ask

When should I use fnmut in C++?

Use FnMut as a bound when you want to accept a parameter of function-like type and need to call it repeatedly, while allowing it to mutate state. If you don’t want the parameter to mutate state, use Fn as a bound; if you don’t need to call it repeatedly, use FnOnce.

What is the difference between fnmut and fnonce?

Since FnOnce is a supertrait of FnMut, any instance of FnMut can be used where a FnOnce is expected, and since Fn is a subtrait of FnMut, any instance of Fn can be used where FnMut is expected. Use FnMut as a bound when you want to accept a parameter of function-like type and need to call it repeatedly, while allowing it to mutate state.

What happens when you call a number that says call out only?

If you call a line that is call-out only, then you won’t get an answer. Usually, a system is in place to prevent ringing, and you might even get an automated message with the correct number to call. Sometimes, that isn’t set up correctly (or at all), and the line will ring until it drops.

Why is my phone not answering incoming calls?

Plenty of call centers will rig the phones to dial out but never answer an incoming call. If you call a line that is call-out only, then you won’t get an answer. Usually, a system is in place to prevent ringing, and you might even get an automated message with the correct number to call.


Video Answer


1 Answers

More specifically, why must f(f(2)) mutably borrow f twice?

The borrows here happen in the order of expression evaluation, and expression evaluation is always left-to-right, even when the expressions in question are trivial variable accesses. The expressions to be evaluated in this code are:

  • f(f(2)) is made up of two subexpressions: f and f(2).
    1. Evaluate the function value, f (and borrow it as &mut because we're calling a FnMut).
    2. Evaluate the argument, f(2).
      1. Evaluate the function value, f; error because it's already borrowed.
      2. Evaluate the argument, 2.
      3. Call the borrow of f with the argument, 2. This is the result of f(2).
    3. Call the borrow of f with the argument, the result of evaluating f(2). This is the result of f(f(2))

The borrow checker could soundly accept this case, but it would require the idea of recognizing that the first borrow hasn't been used yet, which isn't currently a thing in the borrow checker.

like image 173
Kevin Reid Avatar answered Oct 27 '22 06:10

Kevin Reid