Fn FnMut and FnOnce

Closures can capture values from their environment in three ways

You need this context to see the text isn't describing the traits or all values but individual(or groups.)

If any single one is captured the "once" way then the closure can only be called once. If none are captured the "once" way it is still possible to be called only once.

The big problem I see with the text is it mixes up with the traits and should define "the closure’s environment" outside of the once way. Not made very clear is for once there are two moves.

Think I just need to type once one more time. :crazy_face:

2 Likes

Unless it's a move closure, which always capture by moving even when calling the closure does not require moving the value.

While move makes the closure capture by moving, it doesn't change a thing about the whether the closure implements Fn or FnMut, i.e. it can still be called more than once - no extra moves when calling the closure.

1 Like

Plus a move closure can capture an owned ... borrow! :upside_down_face:

This logically doesn't make sense

You can call it at most once through the FnOnce trait, but the same type may implement additional traits like Fn that let you call it more than once.

If the type is FnOnce and it is not Fn or FnMut, then it can be called at most once.

I somewhat really struggle to understand the logic behind it.
Is Trait an interface, if so having FnOnce and Fn or FnMut somehow doesn't make sense that is, Fn or FnMut is a superset of FnOnce. If I understand it correctly of course.
So in other words what difference does it make to have FnOnce and Fn as traits implemented by a closure to closure that implements just Fn?

If you were to have a watch that says "it can go (at most) 5 meters underwater". If you then go, put it 5.5 meters underwater, and it doesn't break, would you go and blame the manufacturer?

This is the same: FnOnce() states "to avoid breaking stuff, may be called at most once". And something that can be called multiple times could adhere to that contract, if it wanted to. But in so doing, it would forfeit that extra capability it initially had, of course.

This is a joke right?
It can either be called at most once or once or more. Having the two in one sentence logically does not make a sense.

This function can be called at most once or one or more times.

Yes, that's correct. This is even reflected in the trait definition:

pub trait FnMut<Args>: FnOnce<Args>

which says that everything that implements FnMut also implements FnOnce. This is because if you have something that is safe to call many times, it is also safe to call it once.

(We'd usually say that FnOnce is the “supertrait” or “superset” here, since the set of types that implements FnMut is a strict subset of the set of types that implement FnOnce.)

To set this straight in the most simple way possible: There are two kinds of closures:

  • some closures can be called at most once
  • some closures can be called an arbitrary amount of times

Those closures that can be called at most once implement FnOnce but don’t implement FnMut or Fn.

Those closures that can be called an arbitrary amount of times implement FnOnce, too, but they also implement FnMut (and some of them also implement Fn, but that’s another kind of distinction).

(This means that every closure implements FnOnce.)


And another thing about supertraits:

FnOnce is a supertrait of FnMut. And FnMut is a supertrait of Fn. This has the effect that it is impossible to have a closure that “just implements Fn”. It has the effect that everything that implements Fn also has to implement FnMut and everything that implements FnMut has to also implement FnOnce.

1 Like

Yes, that how I understand it exactly. Those bullet points you've provided say it very clearly and that is how I understood/understand those Fn* traits. Unfortunately documentation confuses things but providing two contradicting sentences in literally same paragraph.

This^^^. I understand (I believe) what it declares.
It is very confusing in documentation how it is explained with literally contradicting sentences one right next to the other.

Yes, I agree.

1 Like

If you like reading very accurate and detailed descriptions of aspects of the Rust programming language, I can recommend the Rust reference [⟵ link to page about closures]. It is no introductory material, but good for looking up something when you’re interested in “all the details” and don’t feel like asking the compiler (i.e. experimenting) instead.

Thanks, will definitely read that material.

Another remark: An FnMut does not necessarily need to be able to be called more than once successfully. There are strategies to “convert an FnOnce into a FnMut(or convert “an FnMut into an Fn”) that will result in a runtime check that will panic when the converted FnOnce is called more than once (or a runtime check that panics when the converted FnMut is called multiple times concurrently).

pub fn fnonce_to_fnmut<Arg, Res>(f: impl FnOnce(Arg) -> Res) -> impl FnMut(Arg) -> Res {
    let mut some_f = Some(f);
    move |arg| some_f.take().expect("called closure more than once")(arg) // expect can panic
}

pub fn fnmut_to_fn<Arg, Res>(f: impl FnMut(Arg) -> Res) -> impl Fn(Arg) -> Res {
    let f_cell = std::cell::RefCell::new(f);
    move |arg| f_cell.borrow_mut()(arg) // borrow_mut can panic
}

pub fn fnonce_to_fn<Arg, Res>(f: impl FnOnce(Arg) -> Res) -> impl Fn(Arg) -> Res {
    fnmut_to_fn(fnonce_to_fnmut(f))
}

(playground)

2 Likes

Funnily, I've recently had to (ab)use this in order to dyn-ify a FnOnce() without Boxing to work around a limitation regarding recursive types.