You can monkeypatch code in Python pretty easily, but we look down on it enough that we call it "monkeypatching". In Ruby they call it "opening a class" and think it's a cool feature. I will assert: we are right, they are wrong.
Today, I was frustrated by a Rails bug affecting pagination with joins. In short, it doesn’t work. At all.
Miraculously, (no, it wasn’t a coincidence—it was an actual miracle) Kevin Clark posted a message to the Rails Core list right in the middle of this episode complaining about the exact same problem. He said he was working on a fix. Jeremy Hopple responded a little over an hour later saying that he had already submitted a patch for the bug.
Visions of the nasty download/patch process started trudging through my mind, but I was desperate for a fix so I would have dealt with the ugliness. I hate hacking my local Rails (I’m running off of trunk using svn:externals) because I don’t like dealing with what happens when the change actually gets applied to trunk or dealing with merges for other changes to the same files. It’s not rocket science to get working but it’s also not fun.
Looking more closely at Jeremy’s email, he’s also distributing his patch as a Rails plugin. So:
$ ruby script/plugin install count_limit_assocations
Now my code works. The bug is fixed. The plugin contains essentially nothing but a file that "monkey patches" some of the Rails core classes, implementing the changed version of the code.
When the change is merged into the Rails trunk, I’ll just ‘script/plugin remove’ Jeremy’s plugin.
The Rails team is already using plugins like this as a way to get new functionality into circulation as a kind of proving ground before things make it into Rails core. And as we see today, it’s also a simple, painless way to get fixes distributed before they’re reviewed and committed. Sure, you can do the more obvious thing with plugins and distribute code that implements new functionality altogether. But this "monkey patching" thing is seriously powerful and, as an end-usre in this case, I can say that it makes things better for the users of Ruby.
So Ian, with respect, no…you’re not right.
UPDATE: Ian sent me the following clarification by email (reprinted with permission—thanks Ian!):
Hi Chad. Saw your post on monkeypatching. Just thought I'd clarify that I don't think that kind of use is wrong, and I do that frequently -- applying a patch at runtime to the objects in memory, instead of the source code on disk. It can be expedient, and certainly a whole lot better than trading patches around. The use I object to that I see in lots of Ruby examples (and maybe isn't indicative of most real Ruby code) is when people add methods to other classes that aren't meant to fix anything, but just because they don't have an object of their own to hang the method off of. I've seen several examples where people add methods to Array to implement some recursive algorithm, instead of using a function. Or Rails adding methods to numbers to create time delta objects (well, it would be good if they *were* time delta objects, but I understand they actually just return seconds as ints, but that's another issue entirely). The term "monkeypatch" is really meant to denote that. It's a patch, a fix, an adjustment to the code. The monkey part has a history (that someone left on my post) that I think more-or-less is meant to indicate a certain subversive intent, or at least playfully but maybe mischievous manipulation. We do it often in Python, but everytime we do it we know we are working around the system and not with it. Which is fine too, but it's not the sort of thing you want as a foundation.
Sorry, comments are closed for this article.