views:

245

answers:

5

I'm a Ruby coder. For me, monkeypatching is to change, at runtime, classes or modules methods in an external project. What I'm interested in, is what mechanism you have in place that will protect you from some of the abuses of that nice feature. Follows, some scenarios that I have encountered, where monkeypatching has bitten me.

While I don't know Smalltalk at all, that language have been there long before Ruby. I have done some research to see if and how Smalltalk solved some of these problems but didn't find much on Google. So here I am, asking for Smalltalkers if they can share their wisdom.

Scenario A : bug fixing conflict

Project A and B depend on project C. Project C has a bug. Project A and B releases contain a fix for project C.

If your code uses Project A and B, how can you know the patches won't conflict ?

Scenario B : outdated bug fixing

Project C releases a fixed minor version of their project.

If you load project A, will the patch still be applied, with potential breakage ? I'm interested to know if there are some mechanism in place, for example, to not load the patch if the code is fixed.

Scenario C : conflicting extensions

Project A and B use project C's class Foo. Both add a utility method to Foo, say, #toDate. The toDate version of A returns a date string, and the one of B a Date object.

If you load both projects (with C dep), is there a mechanism that will warn/prevent the conflict ? Or will you have to wait until runtime throws an error because of a wrong expectation in a method ?

About the question update

Reading the answers, I realise my question was too broad and vague. So here is a rewritten version of it.

+1  A: 

It says "yeah! Go for it!"

The whole notion really probably showed up in Smalltalk first.

Go to the root class in the class browser, and you can add all the methods to the image you like.

Remember, though, that Smalltalk has a very different picture of the world than the other usual languages (the only other common one like Smalltalk was APL.) You have an image that contains the whole set of code and runtime package. When you change the image, every bit of code in the image is affected. Other images are not changed. You can have change sets to reload your favorite hacks, but they're basically importing code into the image.

Charlie Martin
+1  A: 

Smalltalkers don't use a term 'monkey patching' but I have a feeling that the 'method overriding' is the closest term. That is, an override a method of one class in package A, with a method of the same class in package B. So when you load a package B, the original method in A is overriden.

Method overrides has their advantages but much more disandvantages when not used carefully, so in general we tend to avoid them. It also depends of Smalltalk dialect - in VisualWorks for instance tools supports overrides quite well while in Squeak not so.

Janko Mivšek
+1 for recognizing the importance of term usage in each (sub)culture, -1 for confusing with method overriding (a totally different thing)
Javier
Obviously not so totally different thing, after reading Wikipedia article on monkey patching. Well, it seems that in Smalltalk we are therefore monkey patching simply by changing some method in a live image? We are doing that all the time anyway.
Janko Mivšek
+4  A: 

In Smalltalk, we have traditionally called this overriding. Depending on the version control tools you use with Smalltalk, you either;

-- create a new version of the package that originally owned the class/method(s) in question -- create a new package which will own the override of the class/method(s) in question

In VisualWorks and ObjectStudio (the Smalltalk I'm most familiar with), the latter approach is used. In VA Smalltalk, where Envy is used, the former approach is taken. I believe Squeak would follow the latter approach using Monticello, but I'm not entirely certain.

In most Smalltalk implementations, it's easy to see both the original version of the overridden code, and the currently installed override.

In client applications, overrides really only impact you when you update to a new version of Smalltalk from the venor (or the Squeak team, et. al.). For server apps, where multiple applications may be resident in the server, you need to be much more careful about what you decide to do.

Overrides (or monkey patches, as you call them) are a powerful tool, but you need to be careful about how you use them - and if you do use them, you should re-examine whether you still need them on a regular basis. In my open source news aggregator, BottomFeeder, I've removed a lot of the overrides I put in place initially.

jarober
A: 

Answering to myself, here is my current point of view:

Scenario A and B

Since all code is open, the best practice would be to fix the broken project directly. Tools like git manage code merge already, so we don't need to rely on a runtime mergin, that would not always work.

Depending on the willingness of upstream to merge your fix and speed to release a new version, you might envision to produce a monkeypatch. In that case, the best would be to have a mechanism that say:

monkeypatch(ClassName, :method, &newcode) of the broken project
is applied if project.version in [a set of releases where the bug exist]
if the project version is unknown to the monkeypatch,
  raise an error to tell the developer to fix the monkeypatch (check if bug exist).
if a monkeypatch for that project, classname and method already exist, yell

This is from the top of my head. It might be problematic if a bugfix requires more than a method change.

Scenario C : TODO

zimbatm
+1  A: 

If you are looking for cutting-edge solutions, take a look at Changeboxes. The research prototype of Changeboxes is based on Squeak Smalltalk.

See http://scg.unibe.ch/research/changeboxes

Adrian
Thanks for the pointer !
zimbatm