BT

Ruby's Open Classes - Or: How Not To Patch Like A Monkey

Posted by Werner Schuster on Jul 11, 2008 |

Hello stranger!

You need to Register an InfoQ account or or login to post comments. But there's so much more behind being registered.

Get the most out of the InfoQ experience.

Tell us what you think

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Eric Anderson by Eric Anderson

I take away the opposite lesson from the Symbol#to_proc incompatibility problem. What I take away is "use open classes (within reason) because it will give you great functionality that you need without waiting for some official vendor to support it".



Don't get my wrong. Alternatives should certainly be considered. Open classes are not the solution for every problem and your article lists and explains some great alternatives. But don't be scared of open classes either.



Rails popularized the Symbol#to_proc method and it may not have been included in Ruby 1.9 and backported to Ruby 1.8 had Rails not popularized it. Symbol#to_proc is an extremely useful method that has saved countless developers countless snippets of time. By having open classes Rails was able to include this functionality YEARS before some official vendor supported it. Even once the vendor did support it there was a slight incompatibility which was resolved. Now each case is different. This time the issue was resolved by the official vendor changing their code. Maybe next time the application (or framework) will need to change it's code to get the issue resolved. But either way we traded countless amounts of time saved for just a few moments of "hmmm.... I guess we need to change this to that". Sounds like a big win for me.



Stop being afraid of the dynamic language and embrace it. Have good testing to catch issues like this before deployment and then love the benefits you reap. Don't go back to the old non-agile way of doing things where you write reams of extra convoluted code just to ensure you are not affected by some unlikely issue that might happen in the future.



You are going to have compatibility problems no matter how careful you are. So just use common sense and deal with anything when it comes.

Overstated as Written by Christian Romney

> redefining the method can break the system, i.e. the Ruby stdlib and all it's clients that rely on the behavior of the standard Ruby library.

Only for "clients" in that process or that require the offending library. The way it's written - and with system in italics - it sounds like you can hose the standard library for all Ruby applications running on a box by using open classes.

Patch like a Monkey by Kevin Teague

"putting them all in a file extensions.rb" is a good suggestion, but I would distinguish between opening a class to fix a bug or add a feature *which you intend to eventually make it's way upstream* (aka monkey patching) versus opening a class as a permanent design choice. In the first case, the filename convention in Zope is "patch.py" (and __init__.py being the worst filename location for a monkey patch since those source files are less commonly used and so harder to detect).

There is also a "monkey" package for Python which only applies the patch if a hash signature of the patched method is unchanged, which is an extra careful way of patching so that the developer can be alerted when the upstream source being patched has changed (pypi.python.org/pypi/monkey).

Monkey patching was originally called "guerilla patching" (a term started at Zope Corp.) because a developer who disagreed with a choice made upstream could apply their own behaviour without needing to have the patch reviewed and applied upstream. Guerilla patching was misheard as Gorilla patching and from that the term Monkey patching was invented to sound "less forceful than a gorilla". Zope developers still tend to use this term to only apply to opening classes to fix or extend them to address undesirable behaviour upstream - other use-casses for re-opening a class is usually just called "dynamic class modification". However, in the larger Python and Ruby communities this distinction isn't usually made and Monkey patching usually refers to any re-opening of class, regardless of intent.

The adapter pattern developed in Zope (and the convention-over-configuration technique applied by Grok which avoids the need for XML sit-ups) rocks, and is better alternative in many cases than the venerable monkey patch. Syntactically Python adaptation is much more concise than the Java equivalent :)


Eclipse/Java:
OutlinePage p = editor.getAdapter(OutlinePage.class);



Zope/Python:
p = IOutlinePage(editor)


BTW, it's Zope and not ZOPE, which is akin to saying RUBY or JAVA, all-caps are yucky :P

Re: Overstated as Written by Werner Schuster

Hmm... the word "clients" was meant to mean "clients of libraries", ie. if a piece of your application uses - say - library X, it's a client of that library. I can see how it can be misunderstood as "all apps on the system"... but I thought it was clear that's not really possiblen anyway.

Re: Eric Anderson by Werner Schuster

I agree - having this power definitely gives Ruby an edge and allows tons of experimentation which is impossible or very hard in other systems ("very hard" as in, eg., having to adapt the language's compiler or runtime to do so, etc).
BTW: experimentation like this is fine enough - that doesn't mean that you want to put something like this in a library. We recently had a presentation on how Mingle was built:
www.infoq.com/presentations/ford-rails-based-mi...
One thing that I noticed was the liberal use of Open Classes - something which is fine if you build an application which is _never_ going to be part of something else.
However: if you release a library, you have no idea at all where it'll end up and with which other libraries it'll share an address space.
How would you like it if you just spent a day or two tracking down a problem... only to find out that developers of library A had to slap some odd method on Object, just to save a few keystrokes.

There is, however, the issue that it's very easy to use open classes... and it's very easy to ignore the very real issues.

Mind you: there are ways to avoid these issues _AND_ reap the benefits - I gave a few solutions in other languages (Classboxes, Extension Methods), and there are more which come as a neat side effect of strict enforcement of modularity: eg.
gbracha.blogspot.com/2008/03/monkey-patching.html
Or watch Gilad Bracha's talk on Newspeak:
www.cincomsmalltalk.com/blog/blogView?showComme...

So, yeah: use Open Classes... just don't patch like a monkey...

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

5 Discuss

Educational Content

General Feedback
Bugs
Advertising
Editorial
InfoQ.com and all content copyright © 2006-2014 C4Media Inc. InfoQ.com hosted at Contegix, the best ISP we've ever worked with.
Privacy policy
BT