The reuse doesn’t occur in your own code that you control. There you can just add new operations and types as you wish, so the expression problem doesn’t come up. This may be why so few programmers seem to recognize it as a significant issue — it doesn’t become a major impediment to code reuse until you look at an entire software ecosystem with various independent actors. The issue occurs when one person wants to reuse parts of someone else’s code without them collaborating closely.
Suppose, for example, that you want to add new operations to types that I have defined in one of my packages. OOP makes this sufficiently awkward that it’s often easier to just forgo sharing of types and have many separate and independent implementation of the same concepts. Which is indeed something that we see again and again in OOP ecosystems — duplication of similar types instead of sharing of common types. In Julia, on the other hand, we see collections of common types like Distributions, ColorTypes, StaticArrays, various geometric primitives, etc. and they are reused by anyone who needs such a type anywhere in the ecosystem. Different use cases call for different sets of methods operation on those types, but this is no problem with external functions. The code reuse is the reuse of shared types across otherwise unrelated and uncoordinated packages.
On the flip side, in a functional languages, when someone wants to extend existing functions to new types, they cannot generally do so without editing the definition of the original function. It may happen that by some form of polymorphism—including duck typing—the original definition works; but if not, then there is no recourse but to copy-and-modify the function definition and give it a different name or, of the language allows it, “monkey patch” the original function. Again we lose out on code reuse, this time from not getting to share the logic for generic algorithms. OOP, on the other hand, excels here: it allows writing generic code that can apply to new externally defined types automatically. If, however, you need to specialize some generic operation on more than just the receiver of a method then you are still stuck in OOP whereas multiple dispatch handles this fine.
In summary, OOP allows sharing generic implementations of algorithms but discourages sharing and reusing common data types. Functional programming allows sharing types easily but makes it hard to write generic code that can be applied to entirely new types unless the existing implementation happens to work without any specialization required. Multiple dispatch supports both kinds of code reuse straightforwardly.