Search code examples
rustclosuresfunction-pointers

When should I use function pointers instead of closures?


My understanding is that implementing a function that takes an impl Fn as an argument allows the rust compiler to perform more optimization, but using an impl Fn instead of a function pointer shouldn't be more restrictive. I can also pass a function pointer to a function which accepts an impl Fn, so I'm guessing that function pointer type in Rust is useful only as the generic argument for PhantomData to express type variance, in ffi and in some cases as an alternative to Box<dyn Fn(...) -> ...>.


Solution

    • An impl Fn type is basically hiding a type parameter. Any type parameter, making the function a generic function, requires the function to be recompiled (monomorphized) for each different type passed in to it. Thus, generic functions result in longer compile times, and more generated code, compared to non-generic functions that take only concrete types (such as, here, function pointers). Thus, you might use a function pointer to reduce the total compile time of your project, or the size of the binary.

    • If you need to store the provided function, impl Fn() implies putting it in a Box<dyn Fn()>, and calling it through a vtable. This is one more indirection (one more memory access) than calling a function pointer directly. Function pointers can be stored directly in data structures, e.g. Vec<fn(&mut Foo)>.

      (This doesn't mean that the Box will perform an allocation, though; if the function type is not a capturing closure (which is equivalent to “can be coerced to a function pointer”) then it is a zero-sized type and thus the Box does not allocate.)

    • As you already noted, function pointers appear in FFI because they're the expected ABI, whereas impl Fn or dyn Fn is Rust-specific.