Dynamicism and “monkeypatching”
There seems to be a bit of a disagreement going between Chad Fowler and Ian Bicking about what Pythoneers call “monkeypatching,” Ruby people call “opening a class” and Smalltalkers call “doing the right thing.”
What do I mean? Well, in a bit of commentary by Ian that was sent to Chad, he states:
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.
This is a blurry line in the world of truly dynamic languages, and it reminds me of the absurd notion of final in Java. There are times when I need to extend an existing class to provide additional functionality because that is where it belongs. Sometimes people put things in the wrong place, but the idea is that they should just “write a function” isn’t necessarily the right solution either.
For example, there is a coercion idiom in Smalltalk where you use message names like asString to coerce one thing into another. It is totally appropriate to extend this to allow for further expressiveness of the language.
The important thing is that Smalltalk implementations have a clear way to do this—through class extensions, which can be loaded and unloaded as needed by other systems. Is it perfect? No, but the idea that someone in the past thought of everything that might be needed in the future is a grossly arrogant position to take.
Languages are tools, and the more they try and “protect you,” the more they limit your creativity. There are bad times to extend classes, and bad places to put functionality, but that is something one can’t make generalizations about, and has to be evaluated in the context of the specific system.
This entry was posted at 1:13 pm on 26 January 2006 and is filed under Python, Ruby, Smalltalk. You can follow any responses to this entry through the post-specific RSS 2.0 feed.
Ownership is easily determined by simply asking for the Implementors from the environment. This might be one of the biggest difference between Smalltalk and Python/Ruby—the existance of live-code at all times, real objects, as opposed to text in a file. grep is a poor substitute for this, and might make the situation more difficult to manage.
Namespaces don’t really solve any issue related to methods on objects, only the Class objects themselves really. Smalltalk, however, has a notion of packages (or other things in different implementations) that load and unload as a whole and insert their changes in when loaded and more importantly, remove them when unloaded.
I think it is important to understand that in Smalltalk, the component (often named “packages”) is more than a set of classes. Components in most Smalltalk environments also allow using extensions, which basically add behaviour (methods) to classes in other components. Note that extensions is not used to modify exiting methods, only add new methods. You will only add functionality to other packages you depend upon.
A prime example of proper use of extensions is where a GUI package extents a domain package to let domain objects answer the GUI forms used to display them. For more details, refer to my comment “Use Extensions!” on the following blog post: http://www.cincomsmalltalk.com/userblogs/troy/blogView?showComments=true&entry=3302502495
So in Smalltalk, extensions is not primary a method for changing existing behaviour, but—as wisely stated above—a tool for adding additional functionality “where it belongs”.
Interesting. I think this may have clarified something I’ve been thinking for a while. It does seem reasonable to want to add functionality to an arbitrary class. It’s replacing functionality that’s potentially dangerous and requires finality.
However declaring all methods in a class final is annoying, while just marking the whole class final is relatively easy. I suspect what’s needed is more distinction between subclasses that add new methods and subclasses that override existing methods. Does any language offer this distinction?
P.S. Your spam prevention is locking out blind users. Very uncool. :-(
First, I appologize for the CAPTCHA problem, but unfortunately it’s an issue that I don’t know how to resolve without re-opening the flood of spam that was hitting this blog before. I try to moderate anything that isn’t auto-approved, however, as quickly as possible.
I think you’re right, and there are two different things at discussion here. The first, what Smalltalkers do constantly, which is “open” classes and extend them. This is also hugely used in Objective-C with categories. This is a “good thing.”
The other is “fixing” problems in existing classes. This is much weirder, and more unpredictable because often someone depends on the behavior—erroneous though it may be—for their own subclass behavior. How to know is nearly impossible.
This later thing is less common in Smalltalk, I believe, because method size in most Smalltalk images is substantially smaller than I’ve seen in Ruby or Python—much less Java. It is frowned upon to have a method much larger than a handful of lines, and therefore the possible intricate dependencies are reduced.
Change out the CAPTCHA for SpamKarma2
I have had 0 spam get through since installing it.
[...] Earlier, I wrote about extending classes, I wanted to give a clear example of what I personally think is a good use for this. I’m working on some time-travel stuff. As I’m writing some tests to talk about what I want to the code I’m working on to do, I get to this: [...]
Responses are currently closed, but you can trackback from your own site.
I think there needs to be a clear ownership of code—not necessarily personal, but some sense of what the code is associated with, what implicit expectations it brings with it, who you go to with bugs, etc.
For patches this is understandably vague—they are written by one person who believes that some other code is just plain wrong and should be fixed. It’s a transitional state.
When I add a method to another class in Python or Ruby (I’m not sure how extensions in Smalltalk work) the ownership becomes vague. How can I tell who “1.year” belongs to? Int, the Ruby standard library, the script, Rails…? You can only figure that out by digging into the system, and that just sucks.
If that new method had a namespace, then that would probably work fine. But “1.Rails::year” doesn’t feel any nicer than “Rails::year(1)”, and neither reads nicely (which I assume was the original motivation).
You can have implicit namespaces. Javascript 2 has that. Maybe Smalltalk class extensions work along those terms—I’d be interested to hear a description of that system if it does address this.
In XML you can have a single lexically scoped implicit namespace. But only one. Do I have to choose between “1.Rails::year” and “1.stdlib::abs”? That’s not a very good choice. But then frankly I don’t think “1.year” is a doable extension in any sane sytem.
If you have multiple implicit namespaces (lexically applied), then you can probably make things pretty. I honestly don’t know if that would be easy to understand or not; at least you’d have a constrained number of places to look. But in the case of Ruby and Python methods all exist in one namespace.