JS Monkey-Patching with Symbol (Chill Patching)
I’ll go into:
- Traditional Monkey Patching and why it is Dangerous
- Safe Monkey Patching with Symbol and chill-patch
- Safe Monkey Patching in other Languages
- Why the Pipeline Operator Proposal is Great
Traditional Monkey Patching and why it is Dangerous
“Monkey patching” in JavaScript refers to adding properties to a prototype separately from where the class is first defined. This is an example of monkey-patching `Array` to add a `last` method, which returns the last item in the array:
Traditional monkey patching like in the example above is dangerous and uncool and probably shouldn’t be done. Here’s why:
- The author of `Array` could add a different implementation of `last`, which could break your code which relies on your implementation.
- Elsewhere in your codebase, someone could add a different implementation of `last`, leading to fragile code.
- Elsewhere in your codebase, it will be hard to tell whether `Array` has been patched or not, so other programmers (or you) could accidentally depend on `Array` being patched or not-patched.
Safe Monkey Patching with Symbol and chill-patch
ES2015 Symbol gives us a way to monkey-patch safely. I call this “chill patching”:
I published a small helper, “chill-patch” for making chill patching more declarative. This code does the same thing as the code in the previous example:
Chill Patching is safe because symbols are guaranteed to be unique. So if two programmers want to add a symbol with the same description (‘last’), both properties will co-exist.
Another benefit of chill patching over traditional monkey patching is that Symbols don’t show up with `Object.keys` or `Object.getOwnPropertyNames`—so you can safely patch classes without other programmers noticing the change or being affected by it.
Why Monkey Patch?
The advantage of chill patching over traditional monkey patching is that it’s safe. But why monkey patch at all?
One reason to monkey patch classes is that method calling syntax (as opposed to nested function syntax) can be more readable, especially when using multiple functions:
The method-style syntax can also be nice for readable tests, though I’m not big on English-like code in general:
Maybe these aren’t the most compelling reasons, but chill patching has such a low barrier for entry that these reasons may be enough. In the previous example as well as this next one, you can see that chill-patch works with off-the-shelf functions on npm, which weren’t designed with chill-patch in mind:
Safe Monkey Patching in Other Languages
Good idea or not, safe monkey patching (or something similar) is found in all of these languages, and is implemented differently in all of them. I find this fascinating, especially the Scala and Nim examples:
- Scala Implicit Conversions
- Objective-C Categories
- Haskell Typeclasses and Rust Traits
- Nim method call syntax
The Pipeline Operator: Better than Monkey Patching
The annoying part about monkey patching is having to explicitly patch classes, rather than just jumping in and using functions. It also feels wrong to modify someone else’s class, even if it is safe.
The pipeline operator proposal, if accepted, will add a `|>` operator to JavaScript that has neither of these problems. The example below shows how it works: the nested function call at the top is equivalent to the pipeline
The pipeline operator is from F#, is also implemented in Elm and is similar to Clojure’s threading macro. I hope it comes to JavaScript!
Conclusion
While we’re waiting for the pipeline operator to come to JavaScript, safe monkey patching using symbols and chill-set is an interesting option. At the very least, I hope it’s fun to try out.