Type anonymity need Generics

  1. A closure is essentially an anonymous struct
  2. A function that accepts a closure parameter only needs to restrict the parameter to implement the following traits:
  • Fn
  • FnMut
  • FnOnce

Closures succinctly capture variables from enclosing scopes. Does this have any consequences?

It surely does.

Observe how using a closure as a function parameter requires generics, which is necessary because of how they are defined:

#![allow(unused)]
fn main() {
// `F` must be generic.
fn apply<F>(f: F) where
    F: FnOnce() {
    f();
}
}

When a closure is defined, the compiler implicitly creates a new anonymous structure to store the captured variables inside, meanwhile implementing the functionality via one of the traits: Fn, FnMut, or FnOnce for this unknown type.

This type is assigned to the variable which is stored until calling.

Since this new type is of unknown type, any usage in a function will require generics.

However, an unbounded type parameter <T> would still be ambiguous and not be allowed.

Thus, bounding by one of the traits: Fn, FnMut, or FnOnce (which it implements) is sufficient to specify its type.

// `F` must implement `Fn` for a closure which takes no
// inputs and returns nothing - exactly what is required
// for `print`.
fn apply<F>(f: F) where
    F: Fn() {
    f();
}

fn main() {
    let x = 7;

    // Capture `x` into an anonymous type and implement
    // `Fn` for it. Store it in `print`.
    let print = || println!("{}", x);

    apply(print);
}

This example could be compared with the decrator mode

See also:

A thorough analysis, Fn, FnMut, and FnOnce