The tradeoff in open methods is that they are tricky or impossible to implement efficiently. Thus, they are primarily featured in object systems that value flexibility over raw performance, e.g. various Lisp dialects. Another example is Julia, which then tries to get rid of as much overhead as possible using JIT compilation.
Open methods must be dispatched entirely at runtime, since the set of available methods is not known until runtime. In contrast, classic OOP systems such as those used by C++ and Java know at compile time which methods are available, just not what the target of a call will be. This enables techniques such as vtable based dispatch which are quite efficient. There are some approaches that appear to have open methods, e.g. typeclasses in Haskell, traits in Rust, and extension methods in C#. However, none of these amount to open methods within the meaning of this question. Haskell and Rust have coherence/orphan rules that limit which modules can implement traits/typeclasses. C#'s extension methods are purely static and don't participate in dynamic dispatch. In contrast, Go's interfaces can be used similarly to open methods. After all, the magic that makes Go work is based heavily on runtime reflection.
That open methods cannot use vtables generally indicates that there is a global registry of types and methods which is filled at runtime, and that most method calls must search this table for matching method implementations. This is the case especially when method dispatch doesn't just depend on the first argument, but on multiple arguments (multi-methods). A more limited alternative would be open classes à la Ruby. While such solutions make it possible to implement solutions to the expression problem, this still does not allow us to encode solutions of the expression problem in a type system.
While open methods often use functional notation method(object, arg)
, this is purely syntactic. There is no reason why dot-notation object.method(arg)
would be impossible. Of course, while some autocomplete will be possible, it is not possible to know the entire set of available methods before run-time. In languages that are built around multi-methods, dot notation might be misleading since the first argument might not contribute to method dispatch.