The first part (32) has allocations because f::Function is an abstractly typed field that needs to point to any subtype of Function, so func.f’s type cannot be inferred. The type has to be checked at runtime a.k.a. dynamic dispatch, which requires allocations as far as I know.
The second part (16) don’t have the aforementioned allocations because f::F is concretely typed and inferrable. The remaining allocations are because funcnew in the global scope is uninferrable. If you did const funcnew = justfuncnew(sin), then funcnew.f(0.1) would have no allocations. Alternatively, you could have wrapped the code in a local scope, like:
let
funcnew = justfuncnew(sin)
@allocated funcnew.f(0.1)
end