When you think Ruby, what is your first association? Oh, it's Rails?
Hmm. What is you think Ruby feature? Monkey patching? Yep, me too.
Programmers have stronger and more heated opinions about monkey patching
than adolescent girls have about glitter. Globally modifying class functionality
at runtime? Why yes, that does sound dangerous.
With a little imagination you can imagine a doomsday scenario where
two libraries wrestle with each other continually to replace some
piece of functionality with their own preferred version, and with each
release the library maintainers modify their code to move their
library back to the top of heap1.
However, monkey patching does provide a solution an important problem:
dynamically adding functionality to a class at run-time. Over in Python land we don't
have a great solution to this problem, and we've kind of decided we're okay with that:
better not to have a zoo than have the lions occasionally escape and gnaw on small children.
However, there is a great solution to this problem. One that allows dynamically
adding functionality to a class--nay, to classes--while respecting namespaces
and not mucking up the reasonable assumptions in other peoples' code (primarily
the assumption that a function won't, without warning, suddenly begin behaving
differently, which is a rather important assumption for writing even moderately deterministic
Like many great ideas that have slowly seeped into modern programming languages,
this idea comes from Lisp--more specifically, Common Lisp--but this one in particular
hasn't yet resurfaced in a mainstream language. The solution? Generic functions (also called multi-methods)
like those in CLOS. Let's do a few examples of what Python might be like
if it had generic function based OO.
So the key difference is that some parameters are typed with a class.
Lets say that anything that isn't explicitly typed can be of any type,
so we're using an eclectic mix of strong typing and duck-typing (similar to
The first advantage we get is that we can add functionality to a class
from any module, not just in its class declaration. For example, if
the above code is in a module named PersonModule, then we could write
this code in another module:
p=Person()p.name='Will'p.title='Mr.'greet(p)# print "Hello Mr. Will"farewell(p)# print "Goodbye Mr. Will"
So we can add methods to an object declared in a different module,
but what if we want to override an object's default behavior in
our module? Easy as pie.
deffarewell(Personp):return"k thnx bai %s"%p.name
p=Person()greet_goodbye(p)# prints "Hello Mr. Will, k thnx bai Will"
So that's kind of cool, right? Sure, I'm pulling this out of thin
air and can't even prove to you that what I'm suggesting is possible,
but this is how OO works with CLOS. There is a working precedent.
And it's awesome.
The joy of generic functions goes a bit further than this as well,
giving us some functionality that feels similar to the type matching
found in Erlang or Scala. Consider this code:
defspeak(a):'If none of the more specific patterns match, falls back here.'print"This is a %s"%a
defspeak(Personp):print"My name is %s"%p
defwalk(Personp,Dogd):print"%s takes %s for a walk"%(p,d)
defwalk(Dogd,Personp):print"%s cannot walk %s"%(d,p)
walk(a,b)# "Will takes Leo for a walk"walk(b,a)# "Leo cannot walk Will"walk(a,c)# "Um. That's weird."
For those who have used 'real' pattern matching, this will seem
like a very cumbersome syntax, but fortunately generic methods
don't just give us pattern matching, along with the heavier
syntax comes heavier capabilities:
Rather than only matching on types, the ability to use classes for pattern matching as well.
(You could also phrase this as, classes are a valid type for matching.)
That includes giving us polymorphism by specializing methods on increasingly
specific classes (Programmer instead of Person, PerlProgrammer
instead of Programmer).
Ability to override handling of a specific pattern, without rewriting
the rest of the patterns.
That said, it doesn't necessarily allow for all of the functionality
of pattern matching, because you can't customize the order in which
it will attempt to match the pattern (will always go from more specific
to more general in a predictable and consistent order, while pattern
matching will let you define any ordering
your heart desires)2.
Also, depending on the implementation it might not allow specializing on
values (instead of just types), but it would be fairly intuitive to add
value-specialization to the syntax:
That would open up some pretty interesting doors. Doors I would like to walk through. (Actually, looks like those doors are already discussed here,
and opened here. Now I just need to start walking. Err, and I'd like the syntax to be native. Maybe a pre-compiler of some sort is in order.)
This sounds stupid, doesn't it? It is, and the tragedy is that
something comparable occurs all the time in the worlds of anti-virus
Depending on the specific implementation (basically, where one establishes the
trade-off between explicitly importing all multi-methods you'll use
versus them being implicitly imported when you load a module to save typing),
it is possible to create a predictable system for multiple inheritance,
although at the expense of many many more imports.↩