It's still called monkey patching. Any modification of the class itself that happens far from it's official declaration is monkey patching.
Monkey patching IMO has two main pitfalls:
Method definition become harder to search. When one wants to look at a method's definition they usually go to the class' definition. When the method is monkey patched, the method's code and comments won't be there - or even worse, if the method is replace then the original method will be there, with no indication that it was replaced with something else.
You now depend on hidden module loading. Yes, you were always depending on module loading, but now the dependency becomes more implicit.
Usually you know that if you are creating a new Foo
you need to load foo.js
first(or whatever module Foo
is defined in). Or, if you received a Foo
from somewhere else, you know that foo.js
was loaded there. Even if you somehow created a Foo
without loading foo.js
because someone else loaded it for you, and that someone else removed the command that loads foo.js
, when your code breaks it's usually vert easy to solve - you get an error that Foo
is an unknown identifier, so you look where it's defined and load it.
Monkey patching is not so easy. unrelated.js
may add Foo.bar
, and you may be using it without loading unrelated.js
yourself. Then someone removes it's dependency on unrelated.js
, or maybe you created a new script and just loaded foo.js
, and suddenly your Foo
objects no longer have bar
. You are going to bang your head against the wall several times before you'll realize that you need to load unrelated.js
.
My solution? If you need to use monkey patching, try to limit it to framework and infrastructure code, and not use it in library or application code. This greatly reduces the risks, because:
Framework and infrastructures are already allowed to redefine the rules of the language. Ruby on Rails is a notable example: you are already deeply aware that you are no longer programming Ruby - you are programming RoR - so the monkey patched classes are just another modification you need to be aware of.
Frameworks and infrastructures usually handle their own module loading to guarantee they work properly, so they can guarantee that all the monkey patching code is loaded.
Frameworks and infrastructures have their own conventions, and if you are aware of those you can easily find the definitions of monkey patched methods.
P.S.: Some compiled static languages have some facilities that resemble monkey patching - like extension methods in C# or Rust's struct
/impl
separation. These facilities do not have those pitfalls, because the methods you define do not become part of the class. They are only using the class' namespace, and are still belong to the module/scope they are defined in.