Another approach to child-to-parent communication: passing functions?
I'd be surprised if they don't have this approach documented anywhere. It's pretty standard in other web frameworks, but works for a different kind of communication paradigm to events.
Events keep everything loosely coupled, and if you needed later on to support communications with a component outside of the hierarchy then you'd be good to go, but there are a lot of cases where you know it won't go beyond the child -> parent route and in that case this would work fine.
One thing I would say though is that it often pays to be consistent, so perhaps just using events everywhere is the better option regardless? You'd need a whole lot of messaging going on for the performance overhead to affect a real-world use case, but that's not to say there aren't cases where it'd be the better choice.
Firstly,
this is not documented. As a thumb-rule, salesforce always insists to use ONLY what is documented. So, this may some day be made invalid by salesforce the sameway they did Prevent Creation of Function Expressions in Dynamically Created Aura Components (Critical Update). Although passing function expressions in attributes (properties) of dynamically created components seemed normal, it seems it created memory leaks and they considered it anti pattern (The same way you are passing function expressions to javascript properties in child component). So, even what you are suggesting may become invalid someday according to LWC coding practices as its not documented.
Secondly,
this way of implementing communication is very very limited to strictly child-parent relationship.
Scenario-1: it works in this scenario
<c-parent>
<c-child>
Scenario-2: if you want to use same child or parent in another flow, you will have to implement another relationship between parent/container and container/child
<c-parent>
<c-container>
<c-child>
Clearly, it will lead to much more complicated code compared to events.
Regarding performance difference, its negligible. You just pass data from 1 component to another and a user will never notice any kind of delay or fastness when you choose one over the other.
Conclusion: I would suggest events is the best way to implement communication for bottom up in hierarchy considering above 2 points.