views:

2158

answers:

6

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
+2  A: 

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.

The Wicked Flea
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
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. ;-)
The Wicked Flea
+3  A: 

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

davetron5000
A: 

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

Good follow-up on the subject:

http://www.infoq.com/articles/ruby-open-classes-monkeypatching

maurycy
+7  A: 

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
"...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
+5  A: 

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.

Paul Betts
True, however what I showed was a look-alike method and not an entirely new one.
The Wicked Flea
So what's the term that describes the act of adding new methods (if there is such a term)?
Yaser Sulaiman
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
A: 

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.

method