Why can I not call FnMut twice in a line? - rust

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.

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).
Evaluate the function value, f (and borrow it as &mut because we're calling a FnMut).
Evaluate the argument, f(2).
Evaluate the function value, f; error because it's already borrowed.
Evaluate the argument, 2.
Call the borrow of f with the argument, 2. This is the result of f(2).
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.

Related

Writing generic implementation of sum on an iterator in Rust

I have been learning Rust, coming from a Swift, C and C++ background. I feel like I have a basic understanding of ownership, borrowing and traits. To exercise a bit, I decided to implement a sum function on a generic slice [T] where T has a default value and can be added to itself.
This is how far I got:
trait Summable {
type Result;
fn sum(&self) -> Self::Result;
}
impl<T> Summable for [T]
where
T: Add<Output = T> + Default,
{
type Result = T;
fn sum(&self) -> T {
let x = T::default();
self.iter().fold(x, |a, b| a + b)
}
}
Compiler complains with expected type parameter T, found &T for a + b.
I understand why the error happens, but not exactly how to fix it. Yes, the type of x is T. It cannot be &T because, if nothing else, if the slice is empty, that's the value that is returned and I cannot return a reference to something created inside the function. Plus, the default function returns a new value that the code inside the function owns. Makes sense. And yes, b should be a shared reference to the values in the slice since I don't want to consume them (not T) and I don't want to mutate them (not &mut T).
But that means I need to add T to &T, and return a T because I am returning a new value (the sum) which will be owned by the caller. How?
PS: Yes, I know this function exists already. This is a learning exercise.
The std::ops::Add trait has an optional Rhs type parameter that defaults to Self:
pub trait Add<Rhs = Self> {
type Output;
fn add(self, rhs: Rhs) -> Self::Output;
}
Because you've omitted the Rhs type parameter from the T: Add<Output = T> bound, it defaults to T: hence to your a you can add a T, but not an &T.
Either specify that T: for<'a> Add<&'a T, Output = T>; or else somehow obtain an owned T from b, e.g. via T: Copy or T: Clone.

return closures but cannot infer type

When learning rust closures,I try Like Java return "A Function"
fn equal_5<T>() -> T
where T: Fn(u32) -> bool {
let x:u32 = 5;
|z| z == x
}
But when i use it
let compare = equal_5();
println!("eq {}", compare(6));
Build error
11 | let compare = equal_5();
| ------- consider giving `compare` a type
12 | println!("eq {}", compare(6));
| ^^^^^^^^^^ cannot infer type
|
= note: type must be known at this point
See: https://doc.rust-lang.org/stable/rust-by-example/trait/impl_trait.html
Currently T simply describes a type, which in this case implements the Fn trait. In other words, T isn't a concrete type. In fact with closures, it's impossible to declare a concrete type because each closure has it's own unique type (even if two closures are exactly the same they have different types.)
To get around directly declaring the type of the closure (which is impossible) we can use the impl keyword. What the impl keyword does is convert our description of a type (trait bounds) into an invisible concrete type which fits those bounds.
So this works:
fn equal_5() -> impl Fn(u32) -> bool {
let x:u32 = 5;
move |z| z == x
}
let compare = equal_5();
println!("eq {}", compare(6));
One thing to note is we can also do this dynamically. Using boxes and the dyn trait. So this also works, however incurs the associated costs with dynamic resolution.
fn equal_5() -> Box<dyn Fn(u32) -> bool> {
let x:u32 = 5;
Box::new(move |z| z == x)
}
let compare = equal_5();
println!("eq {}", compare(6));
The compiler seems to be complaining that it's expecting a type parameter but finds a closure instead. It knows the type, and doesn't need a type parameter, but also the size of the closure object isn't fixed, so you can either use impl or a Box. The closure will also need to use move in order to move the data stored in x into the closure itself, or else it wont be accessible after equal_5() returns, and you'll get a compiler error that x doesn't live long enough.
fn equal_5() -> impl Fn(u32) -> bool {
let x:u32 = 5;
move |z| z == x
}
or
fn equal_5() -> Box<Fn(u32) -> bool> {
let x:u32 = 5;
Box::new(move |z| z == x)
}

What is the difference between "eq()" and "=="?

This is what the std says:
pub trait PartialEq<Rhs: ?Sized = Self> {
/// This method tests for `self` and `other` values to be equal, and is used
/// by `==`.
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
fn eq(&self, other: &Rhs) -> bool;
/// This method tests for `!=`.
#[inline]
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
fn ne(&self, other: &Rhs) -> bool {
!self.eq(other)
}
}
And the link: https://doc.rust-lang.org/src/core/cmp.rs.html#207
This is my code:
fn main() {
let a = 1;
let b = &a;
println!("{}", a==b);
}
and the compiler told me:
error[E0277]: can't compare `{integer}` with `&{integer}`
--> src\main.rs:4:21
|
4 | println!("{}", a==b);
| ^^ no implementation for `{integer} == &{integer}`
|
= help: the trait `PartialEq<&{integer}>` is not implemented for `{integer}`
But when I used eq(), it compiled:
fn main() {
let a = 1;
let b = &a;
println!("{}", a.eq(b));
}
It's actually quite simple, but it requires a bit of knowledge. The expression a == b is syntactic sugar for PartialEq::eq(&a, &b) (otherwise, we'd be moving a and b by trying to test if they're equal if we're dealing with non-Copy types).
In our case, the function PartialEq::eq needs to take two arguments, both of which are of type &i32. We see that a : i32 and b : &i32. Thus, &b will have type &&i32, not &i32.
It makes sense that we'd get a type error by trying to compare two things with different types. a has type i32 and b has type &i32, so it makes sense that no matter how the compiler secretly implements a == b, we might get a type error for trying to do it.
On the other hand, in the case where a : i32, the expression a.eq(b) is syntactic sugar for PartialEq::eq(&a, b). There's a subtle difference here - there's no &b. In this case, both &a and b have type &i32, so this is totally fine.
The difference between a.eq(b) and a == b in that dot operator does autoref/autoderef on receiver type for call-by-reference methods.
So when you write a.eq(b) compiler looks at PartialEq::eq(&self, other: &Rhs) signature, sees &self reference and adds it to a.
When you write a == b it desugars to PartialEq::eq(a, b) where a: i32 b: &i32 in your case, hence the error no implementation for `{integer} == &{integer}` .
But why it does not do the same in operators? See
Tracking issue: Allow autoderef and autoref in operators (experiment) #44762
Related information:
What are Rust's exact auto-dereferencing rules?

How lifetime parameters and borrowing interacts in function signatures

Lets say I have a function with the following signature in Rust:
fn f<'a>(x: &'a i32) -> &'a i32;
Lets say I do the following then:
let x = 0;
let y = f(&x);
In that case, the Rust borrow checker considers y to borrow x. Why? What is the reason on a deeper level than "because you used the same lifetime parameter in the parameter type and the return type".
The function signature
fn f<'a>(x: &'a i32) -> &'a i32;
means that the value returned by f is a reference to what x parameter refers to, hence it can't outlive it. For example, this won't work:
// Compile error
let y = {
let x = 0;
f(&x)
// x is dropped here
};
// Here y still "exists", but x doesn't (y outlives x)
To your specific question:
Lets say I do the following then:
let x = 0;
let y = f(&x);
In that case, the Rust borrow checker considers y to borrow x. Why?
The answer is because the function signature of f tells it so. To give you an example, suppose that we change the signature to this:
fn f<'a, 'b>(x: &'a i32, z: &'b i32) -> &'a i32;
Then we call f like this:
let x = 0;
let z = 1;
let y = f(&x, &z);
In the code above, y borrows x, but not z. It's because the return value of f has 'a lifetime that is the same as x's lifetime.
Using the syntax from the Rustonomicon, we can elaborate the second snippet
let x: i32 = 0;
'a: { // definition of a lifetime (not real syntax)
let y: &'a i32 = f::<'a>(&'a x) // &'a x is also not real, though interestingly rustc recognizes it
}
The lifetime 'a is introduced by the compiler because you wrote a & and it needs to know how long that borrow will last (note that you cannot manually specify lifetimes for borrows). The type of the function also means that y has 'a in its type. The compiler needs to figure out where 'a starts and ends. The rules are that 'a must start right before you perform the borrow, that x cannot be moved during 'a (since it's borrowed), and that y cannot be used after 'a (because its type says so). If the compiler can pick start and end points for 'a so that the rules hold, then it compiles. If it can't, there's an error. There is no direct relationship between x and y; it goes through the lifetime 'a that they both interact with. E.g. you can't move x and then read *y because 'a must end before you move x and after you read *y, but such a time does not exist. TL;DR think about borrow checking as lifetime inference.

Types of unboxed closures being unique to each

This is in the context of the question at Error message with unboxed closures. The answers point out that Rust generates a type each that is unique to each closure, since each of them can potentially capture a different set of variables from the enclosing scope(s).
Here is my question. The two different closure types in that FizzBuzz example are labelled differently, but look identical. How does the compiler resolve the closure type differences while still looking at the identical signatures of the type parameters?
This gap between what the compiler sees and what the programmer sees is confusing.
Thanks.
Edit: By the way, Rust Reference document Section 8.1.10 does not yet say anything about this.
Again, I want to start with the same example as in that answer. Compare this:
fn show_both_1<S: Show>(x: S, y: S) {
println!("{:?} {:?}", x, y);
}
and this:
fn show_both_2<S1: Show, S2: Show>(x: S1, y: S2) {
println!("{:?} {:?}", x, y);
}
(now using {:?} instead of {} because of the recent changes)
The first function requires that both arguments must have the same type, even though this type can be arbitrary as long as it implements Show:
show_both_1::<i32>(1i32, 2i32); // ok
show_both_1::<f64>(1.0f64, 2.0f64); // ok
show_both_1::<???>(1i32, 2.0f64); // not ok!
Obviously the last function call does not make sense, because types of the arguments are different, but the function wants them to have the same type. You can't even write the type parameter explicitly - should it be i32 or f64?
The second function allows different types, so all of these calls are ok:
show_both_2::<i32, i32>(1, 2);
show_both_2::<f64, f64>(1.0, 2.0);
show_both_2::<i32, f64>(1, 2.0);
Now for each argument a different type parameter is used, so it is perfectly fine to pass values of different types, as long as both of these types implement Show.
Absolutely the same thing happens with closures. For each closure the compiler generates a new unique type which implements one of Fn* traits. These types are anonymous, so you can't name them:
let f: ??? = |&: x: i32, y: i32| x + y;
There is nothing you can write instead of ??? above, but there is no need to because the compiler knows which type it has generated for the closure and so it can infer f's type. What really does matter is that this anonymous type will always implement one of special traits: Fn, FnMut or FnOnce. Consequently if you want your function to accept a closure, you need to pass it an instance of some type which implements one of these traits.
But this is natural job for generics! They are usually used when you want your function to accept some arbitrary type which implements some known trait, and situation with closures is absolutely the same. So you have this:
fn call_closure<F: FnMut(i64) -> bool>(f: F) -> bool {
f(10)
}
Because this function argument has generic type, this function can be used with any type which implements FnMut(i64) -> bool trait (which is just a shorthand for FnMut<(i64,), bool>, including anonymous types for closures generated by the compiler:
call_closure(|x| x > 10);
call_closure(|x| x == 42);
The compiler will generate a unique type for each of these closures, but since these generated types will implement FnMut(i64) -> bool trait, call_closure will happily accept both of them.
The situation with different type parameters which I described in the beginning naturally extends to closures because the same mechanism is used here, that is, traits.
fn call_closures_2<F: FnMut(i64) -> bool>(f1: F, f2: F) -> bool {
f1(10) && f2(20)
}
This function accepts two arguments which must be of the same type as long as this type implements FnMut(i64) -> bool trait. And this means that this invocation won't work:
call_closures_2(|x| x > 9, |x| x == 20)
It won't work because these closures have unique, i.e. different types, but the function requires that the types must be the same. For example, this does work:
fn call_closures_3<F: Fn(i64) -> bool>(f1: &F, f2: &F) -> bool {
f1(10) && f2(20)
}
let f = |&: x: i64| x == 10;
call_closures_3(&f, &f);
Note that the function arguments must still be of the same type (now references for the convenience of the example), but since we call it with references to the same closure, their type is the same, and everything works fine. This is not very useful though because it is very limiting - usually you want to provide different closures to functions which takes several ones.
For this reason the function needs separate type parameters in order to accept different closures:
fn call_closures_4<F1, F2>(f1: F1, f2: F2) -> bool
where F1: FnMut(i64) -> bool,
F2: FnMut(i64) -> bool {
f1(10) && f2(20)
}
call_closures_4(|x| x >= 9, |x| x <= 42)
Now type parameters are independent, and even though closures have different anonymous types, it is ok to call this function with them: F1 will become the generated type of the first closure and F2 will become the generated type of the second closure.
Every single closure that is written has a unique type. The compiler basically turns it into a structure with fields to store each variable that is closed over, and implements one of the Fn* traits (Fn, FnMut and FnOnce) for it with an appropriate signature, e.g. Fn(i64) -> bool, a.k.a. Fn<(i64,), bool>.
This is why it is using the regular generic constraint syntax, because that is exactly what is going on.
The word "signature" implies that the two closure types are the same, but they aren't. It's more useful to look at them as constraints. For reference:
fn fizzbuzz<F1, F2>(n: i64, f: F1, fs: &str, b: F2, bs: &str)
where F1: Fn(i64) -> bool,
F2: Fn(i64) -> bool
This doesn't say "F1 is the type Fn(i64) -> bool", it says: "F1 must be a type which implements the Fn(i64) -> bool signature". It's like how there are many different types which implement the Iterator trait, but which all implement the same interface.
In fact, things like Fn(i64) -> bool are actually just traits in disguise, but (if I recall correctly), the syntax for this isn't quite ready yet. In earlier versions, you could write this as Fn<(i64,), bool>.

Resources