71

According to Wikipedia, a monkey patch is:

a way to extend or modify the runtime code of dynamic languages [...] without altering the original source code.

The following statement from the same entry confused me:

In Ruby, the term monkey patch was misunderstood to mean any dynamic modification to a class and is often used as a synonym for dynamically modifying any class at runtime.

I would like to know the exact meaning of monkey patching in Ruby. Is it doing something like the following, or is it something else?

class String
  def foo
    "foo"
  end
end
Mechanical snail
  • 29,755
  • 14
  • 88
  • 113
Yaser Sulaiman
  • 3,311
  • 2
  • 28
  • 25

8 Answers8

66

The best explanation I heard for Monkey patching/Duck-punching is by Patrick Ewing in RailsConf 2007

...if it walks like a duck and talks like a duck, it’s a duck, right? So if this duck is not giving you the noise that you want, you’ve got to just punch that duck until it returns what you expect.

RSK
  • 17,210
  • 13
  • 54
  • 74
52

The short answer is that there is no "exact" meaning, because it's a novel term, and different folks use it differently. That much at least can be discerned from the Wikipedia article. There are some who insist that it only applies to "runtime" code (built-in classes, I suppose) while some would use it to refer to the run-time modification of any class.

Personally, I prefer the more inclusive definition. After all, if we were to use the term for modification of built-in classes only, how would we refer to the run-time modification of all the other classes? The important thing to me is that there's a difference between the source code and the actual running class.

In Ruby, the term monkey patch was misunderstood to mean any dynamic modification to a class and is often used as a synonym for dynamically modifying any class at runtime.

The above statement asserts that the Ruby usage is incorrect - but terms evolve, and that's not always a bad thing.

Joshua Swink
  • 3,380
  • 3
  • 29
  • 27
  • 3
    "...different folks use it differently." After reading the answers here and on the Ruby-Talk mailing list, I realized that you are absolutely right. The term had a more specific meaning when it was first coined, but - as you've said - "terms evolve, and that's not always a bad thing." – Yaser Sulaiman Dec 29 '08 at 14:43
22

Monkey patching is when you replace methods of a class at runtime (not adding new methods as others have described).

In addition to being a very un-obvious and difficult to debug way to change code, it doesn't scale; as more and more modules start monkey patching methods, the likelihood of the changes stomping each other grow.

Ana Betts
  • 73,868
  • 16
  • 141
  • 209
  • True, however what I showed was a look-alike method and not an entirely new one. – Robert K Dec 26 '08 at 20:42
  • 3
    So what's the term that describes the act of adding new methods (if there is such a term)? – Yaser Sulaiman Dec 26 '08 at 20:48
  • 2
    If two different libraries add the same method to the same class, then one will always *replace* the other. It doesn't matter that both are only *adding* methods. Adding is still monkey patching. At least, that's how the Ruby community uses the term. Python uses it differently. – Jörg W Mittag Dec 27 '08 at 13:43
4

This is monkey patching:

class Float
  def self.times(&block)
    self.to_i.times { |i| yield(i) }
    remainder = self - self.to_i
    yield(remainder) if remainder > 0.0
  end
end

Now I imagine this might be useful sometimes, but imagine if you saw routine.

def my_method(my_special_number)
  sum = 0
  my_special_number.times { |num| sum << some_val ** num }
  sum
end

And it breaks only occasionally when it gets called. To those paying attention you already know why, but imagine that you didn't know about the float type having a .times class-method and you automatically assumed that my_special_number is an integer. Every time the parameter is a whole number, integer or float, it would work fine (whole ints are passed back except when there is a floating-point remainder). But pass a number with anything in the decimal area in and it'll break for sure!

Just imagine how often this might happen with your gems, Rails plugins, and even by your own co-workers in your projects. If there's one or two little methods in there like this and it could take some time to find and correct.


If you wonder why it breaks, note that sum is an integer and a floating-point remainder could be passed back; in addition, the exponential sign only works when types are the same. So you might think it's fixed, because you converted bother numbers to floats ... only to find that the sum can't take the floating-point result.

Community
  • 1
  • 1
Robert K
  • 30,064
  • 12
  • 61
  • 79
  • 1
    While it's not always a good idea to monkey patch, you certainly wouldn't take months to find the origin of the bug since it would show up in the stack. – krusty.ar Dec 26 '08 at 19:38
  • 1
    Yes, but imagine it in a large Rails web app, where it functions right 99% of the time. Now you must comb the logs to find out why it fails, and that could take a good deal of work. ;-) – Robert K Dec 26 '08 at 19:45
  • This is a good real-world example of why monkey patching is dangerous – emery Apr 06 '16 at 04:46
  • 1
    A bug in any method would require combing through logs. This is not related to "monkey patch"es. In C# you can extend classes in much the same way and nobody complains about that. Complaining about "monkey patch"es is just a meme most people repeat without giving it much thought. That said, I agree with @emery in that monkey patching *like this* is dangerous because it changes the existing standardized method which means it may behave differently even if there are no bugs in it and an unsuspecting programmer might use it in the wrong way. A good idea is to make your IDE mark such methods. – nurettin Oct 04 '16 at 10:14
  • "This is monkey patching: .... see why monkey patching is bad?" – David Ljung Madison Stellar May 09 '22 at 17:04
4

You are correct; it's when you modify or extend an existing class rather than subclass it.

davetron5000
  • 24,123
  • 11
  • 70
  • 98
3

In Python monkeypatching is referred to a lot as a sign of embarrassment: "I had to monkeypatch this class because..." (I encountered it first when dealing with Zope, which the article mentions). It's used to say that it was necessary to take hold of an upstream class and fix it at runtime instead of lobbying to have the unwanted behaviors fixed in the actual class or fixing them in a subclass. In my experience Ruby people don't talk about monkeypatching that much, because it's not considered especially bad or even noteworthy (hence "duck punching"). Obviously you have to be careful about changing the return values of a method that will be used in other dependencies, but adding methods to a class the way that active_support and facets do is perfectly safe.

Update 10 years later: I would amend the last sentence to say "is relatively safe". Extending a core library class with new methods can lead to problems if somebody else gets the same idea and adds the same method with a different implementation or method signature, or if people confuse extended methods for core language functionality. Both cases often happen in Ruby (especially regarding active_support methods).

method
  • 782
  • 4
  • 10
  • That makes sense. Python is a bit more disciplined with the principle of least surprise, and least magic, in general, so changing builtins to have new contracts or behaviors is considered a bit rude. Ruby however favors conciseness , occasionally at the expense of added magic. Theres a lot of things in ruby that would never be accepted by Pythons decision making process, for better or worse (upside: No implicit returns. downside: no anonymous functions, etc etc) – Shayne Feb 06 '18 at 08:30
3

Explanation of the concept without code:

It means you can "dynamically" modify code. Wanna add a method "dynamically" to a particular class known only at "runtime"? No problem. It's powerful, yes: but can be misused. The concept "dynamically" might be a little too esoteric to understand, so I have prepared an example below (no code, I promise):

How to monkey patch a car:

Normal Car Operations

How do you normally start a car? It’s simple: you turn the ignition, the car starts!

Great, but how can we "monkey patch" the car class?

This is what Fabrizzio did to poor Michael Corleone. Normally, if you want to change how a car operates, you would have to make those changes in the car manufacturing plant (i.e. at "compile" time, within the Car class ^**). Fabrizzio ain't got no time for that: he monkey patches cars by getting under the bonnet to surreptitiously and sneakily rewire things. In other words, he re-opens the Car class, makes the changes he wants, and he's done: he's just monkey patched a car. he done this "dynamically".

You have to really know what you are doing when you monkey patch otherwise the results could be quite explosive.

Fabrizzio, where are you going?

Boom!

Monday, Tuesday, Wed-nes-day, Thursday, Friday, Sat-a-day. Image is free and open source from unsplash - https://unsplash.com/photos/dyrehVIidQk

Like Confucius Say:

"Keep your source code close, but your monkey patches closer."

It can be dangerous.

^** yes i know, dynamic languages.

BenKoshy
  • 33,477
  • 14
  • 111
  • 80
1

Usually it is meant about ad-hoc changes, using Ruby open classes, frequently with low quality code.

Here's a good follow-up on the subject.

Cadoiz
  • 1,446
  • 21
  • 31
maurycy
  • 1,477
  • 1
  • 9
  • 7