A distinction must be drawn between the abstractions of the language and how these may be implemented.
Yes, every function parameter is first a "local", and yes, most locals are implemented as stack variables. But when the optimizer kicks in, it can inline / reorganize most of this stuff. So, for instance, both your local
a, or my anonymous local can be fed directly to the functions consuming it, without needing to construct the value in the stack beforehand.
However, the optimizer can only do changes that do not affect the semantics of the program. And one very hidden semantic of
Box::new(<expr>) is that:
<expr> is created;
An allocation to hold it is attempted;
Then the value is moved to the heap,
2. fails (e.g., out of memory), then it may panic, so this local must be dropped.
- And even it instead of
panic!-king it aborted, then since the creation of
<expr> might have had side-effects it needs to happen whatever the result of the allocation.
This prevents an optimizer to inline / move the creation of the struct directly into its backing (heap) allocation.
Box::alloc().init(<expr>), expresses the following semantics:
With these semantics the optimizer is allowed to inline the creation of
<expr> directly into the heap.