Heap-allocating every closure when a generic parameter would inline.
Box<dyn Fn> has a fixed size and avoids generic noise in signatures.
Every call goes through a vtable and the heap allocation defeats inlining. The boxed closure can no longer be specialised by the optimiser — costly in a hot loop.
Take the closure as a generic: fn run<F: FnOnce()>(f: F). Use Box<dyn Fn> only
when you genuinely need to store heterogeneous closures together.
Canonical alternative
trait-system/trait-objects