Difference between `fn` and `Box<dyn Fn>`

I have a question about fn vs Fn:
Why does:

type MyFn = fn(i32)->i32;

work just as well as:

type MyFn = Box<dyn Fn(i32)->i32>;

in

fn apply_fn(f: MyFn, v: i32) -> i32 { f(v) }

I read the fn is actually a reference to the function pointer somewhere but its confusing if fn is a Type...

1 Like
  • fn is a function pointer. It is just a plain memory address where a function starts which requires that there are values provided (The arguments), it follows a certain abi (The "abi" in extern "abi" fns) and what values are returned.
  • Fn, FnOnce, FnMut are all the traits which describe calling a function. These are generally referred to as the Fn* family. These traits will permit you to use call syntax. If f is a value whose type implements Fn (We'll use this for the example since this makes it the easiest to explain), then we can call f using the standard function call syntax: f(x) or f(), etc. (Note however, that if f is a field on a type, then we must say (my_val.f)()). This is considered an operator, and is therefore under std::ops.
  • Box<dyn Fn()> is a boxed up value which implements Fn. That means, that it could be a closure, fn pointer, or a custom type. Note that fn-style pointers will automatically implement all of the Fn*. This is actually one of the most impeding forms of function values, since you must box it up, and call it through dynamic dispatch (Which has its own downsides for speed).
  • A generic parameter, be it fn foo<F: Fn()>(my_func: F), or using impl syntax: fn foo(my_func: impl Fn()) would be the best choice (But not the most flexible for you, the one who's implementing the function foo). It allows either of the two I discussed above, or, a special third one:
  • Specific function pointers. They're special. They have an unnameable type and are actually the function that they point to. They're not the address, they're the function name. They can implicitly coerce into fn pointers, to not break code like the following:
    fn foo() {}
    let x: fn() = foo;
    
    But, they allow optimizations to occur like as if the receiver were actually calling the function, and not just an opaque pointer.

Thanks for reading my spiel about function pointers, have a nice day.

Read @RustyYato's Closures: Magic Function post for more info on how closures work.


PS. You can write code using the following syntax on the forum:

```
code
```
11 Likes

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