I found an interesting piece via Reddit about composition for something I only just learned recently. What resounded with me most is:
I think the real composability and reusability in object-oriented code doesn’t come from object-oriented design at all: it comes from abstraction and encapsulation. If a library manages to hide a potentially complex implementation behind a simple interface, and you only have to know the simple interface to use it, then that doesn’t come from some inherent property of object-orientation, but a basic module system that limits which symbols are exported to other modules, whether the modules are classes, namespaces, packages or something else.
He goes on to talk about applying these same concepts to functions.
It’s so simple to understand compared to the numerous and perhaps even indescribable ad hoc compositions possible in OOP. If you have two functions with matching input and output types, they always compose!