# Design Notes ## Performance Impact of Boxing Futures `future_form` uses `BoxFuture` and `LocalBoxFuture` under the hood. This section discusses the performance implications of that choice. ### Costs **Allocation** - One heap allocation per boxed future (typically small, but adds up in hot paths) - Deallocation when the future completes **Indirection** - Virtual dispatch through the `dyn Future` trait object on each poll - Pointer chasing can hurt CPU cache locality ### In Practice The impact is often negligible because: 1. Futures are usually polled relatively few times compared to the work they represent 2. A single network call or disk read dwarfs the cost of one allocation 3. The allocator is highly optimized for small, short-lived allocations ### When It Matters - Tight loops spawning thousands of tiny futures - Latency-critical code paths (microsecond-level) - Embedded/`no_std` environments with constrained allocators ### Alternatives | Approach | Tradeoff | |---------------------------------|-----------------------------------------------------------------------------------| | `async-trait` | Same cost (also boxes) | | `impl Future` (static dispatch) | Avoids boxing but can't be used in trait objects or with this kind of abstraction | | Enum-based dispatch | Works for a fixed set of variants, but doesn't generalize | ### Recommendation For most async code doing I/O, the boxing cost is noise. If profiling shows it's a bottleneck, you'd typically avoid the abstraction entirely in that hot path rather than try to optimize the boxing.