Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Monkeypatching is Destroying Ruby

70 views
Skip to first unread message

Avdi Grimm

unread,
Feb 23, 2008, 4:07:36 PM2/23/08
to
Hi folks,

I wrote a blog post with the intentionally provocative title above,
which can be found here:

http://avdi.org/devblog/?p=18

While the title is a bit of deliberate hyperbole, I am genuinely
troubled about the popularization of monkey patching in the Ruby
community. I explain my reasons more thoroughly in the post, but
here's a synopsis:

Monkeypatching has become the hip thing to do in the
Ruby and (especially?) Rails communities, and it has
reached the point where experienced programmers are
turning to it as the tool of first resort *even* when there
is a simpler, more traditional solution available. I
suggest that it's time for Ruby hackers to start setting a
better example.

My hope with this post is to start a conversation about fostering
robust software extension mechanisms in the Ruby ecosystem. I welcome
any comments, both here and on the blog.

--
Avdi

P.S. Before anyone accuses me of it, yes, this is a kind of
self-promotion. But I really do want to start a conversation about
this, and no one reads my blog.

Gregory Seidman

unread,
Feb 23, 2008, 4:38:54 PM2/23/08
to
On Sun, Feb 24, 2008 at 06:07:36AM +0900, Avdi Grimm wrote:
> Hi folks,
>
> I wrote a blog post with the intentionally provocative title above,
> which can be found here:
>
> http://avdi.org/devblog/?p=18
[...]

> My hope with this post is to start a conversation about fostering
> robust software extension mechanisms in the Ruby ecosystem. I welcome
> any comments, both here and on the blog.

I read the post. I think it is both futile and wrongheaded. Futile, because
I don't think it will change anyone's opinion. Wrongheaded, because I think
it's a filtering problem rather than an approach problem.

For any community of open source software, there will be lots of code
released. A lot of it will be crap. Consider CPAN; it's full of
implementations and reimplementations of the same APIs, functionality, and
bindings to C libraries. Some of the packages are good, but a lot of them
are crap. How do you tell the crap from the good? That's a filtering
problem. Trying to get people to only release good code is utterly futile.

So you had a problem with UnitRecord. Its code smelled bad to you. You
reimplemented the functionality in NullDB in a way that doesn't smell as
bad. Assuming it works equally well (I haven't had occasion to use either),
there are now two implementations of the same functionality, one of which
is, for some metric, better than the other. Should the worse one never have
been written/released? What a silly thought. Even if it shouldn't have
been, there's no means to control it (nor should there be, in my opinion).
Furthermore, would you have thought to write your "better" implementation
if the "worse" implementation hadn't been there as an example? Maybe, maybe
not.

There's an argument, usually in the context of test-driven development, for
doing the simplest thing that works. Well, you say, it doesn't work. No, it
*no longer* works for your purposes. That's when you need to revisit it. If
a piece of code implementing functionality you need is causing problems,
you need to either fix it or find/build a new implementation of that
functionality.

Monkey patching can cause problems, but it makes it easy to get things
working quickly. There's a lot of value in that. Until it breaks, it's a
win. When and if it breaks, it's time to fix or replace it. This is true of
any number of other techniques (e.g. relying on Rails-generated SQL until
there are performance problems).

So don't lament that people are using this tool to increase their
productivity, and that it sometimes gets in the way of your productivity
when you reuse their code. Rejoice that someone thought of useful
functionality and implemented it for you, and fix/replace it if it doesn't
suit your needs. If you are dedicated to never releasing code that includes
monkey patches, more power to you. Don't expect anyone else to follow that
lead.

As a side note, I had a knee-jerk reaction to ignore the entire post when
you brought up dependency injection and robustness. It shows a very
enterprisey (in the worse possible way) perspective. You and your team were
capable of figuring out and fixing your problems. Your reaction to a hard
problem should not be to promote "practices" to make it easier for less
capable programmers; it should be (as it was with NullDB) to solve the
problem and release your solution for everyone's benefit.

> Avdi
--Greg


Avdi Grimm

unread,
Feb 23, 2008, 5:04:55 PM2/23/08
to
On Sat, Feb 23, 2008 at 4:38 PM, Gregory Seidman
<gsslis...@anthropohedron.net> wrote:
> I read the post. I think it is both futile and wrongheaded. Futile, because
> I don't think it will change anyone's opinion. Wrongheaded, because I think
> it's a filtering problem rather than an approach problem.

Thanks for reading it! I appreciate your feedback.

> are crap. How do you tell the crap from the good? That's a filtering
> problem. Trying to get people to only release good code is utterly futile.

I want to make it clear that I never called for only releasing good
code, or for some kind of control over what kind of code is released.
80% of everything will always be crap; but there's still value in
setting a good example.

> There's an argument, usually in the context of test-driven development, for
> doing the simplest thing that works. Well, you say, it doesn't work. No, it
> *no longer* works for your purposes. That's when you need to revisit it. If
> a piece of code implementing functionality you need is causing problems,
> you need to either fix it or find/build a new implementation of that
> functionality.

I think there's a misunderstanding here - I used the example I did
because it was a case where the initial solution was *not* the
simplest thing that could possibly work. I obviously cannot speak for
Dan's thought process, but to me it appeared an example of having
gotten into the habit of always reaching for the monkey wrench (if
you'll excuse the pun) first, even when it's not the most pragmatic
tool. Whether or not this was the case with UnitRecord, it is
definitely an attitude I've seen more and more lately.

It's this habit that I'm trying to combat, because I think a lot of
times monkey patching not only hurts productivity in the long term, it
hurts it in the short term too. Monkey patching is *not* always the
shortest distance between two points. It's tricky and prone to subtle
bugs. I do not agree that monkey patching is usually the quick &
dirty solution - often it's the slow & dirty solution.

Unfortunately, along with the assumption that monkey patching is the
easiest way to get things done comes the assumption that if anyone
wants to extend your code they can always monkey patch, so there's no
point providing extension points.

Again, thanks for the alternate point of view.

--
Avdi

Eric Mahurin

unread,
Feb 23, 2008, 5:23:03 PM2/23/08
to
[Note: parts of this message were removed to make it a legal post.]

On Sat, Feb 23, 2008 at 3:07 PM, Avdi Grimm <av...@avdi.org> wrote:

> Hi folks,
>
> I wrote a blog post with the intentionally provocative title above,
> which can be found here:
>
> http://avdi.org/devblog/?p=18
>

I don't agree with the title, but I agree almost everything you said. When
I first starting using ruby a few years ago, I thought the idea "monkey
patching" was a very powerful and useful technique. Later, I came to the
same conclusions as you. I know we are in the minority. I believe that
"monkey patching" in packages can easily kill interoperability with other
packages.

I think this comment of yours hits the nail on the head:

"And this is really the point. Monkey patching is the new black. it's what
all the hip kids are doing. To the point that smart, experienced hackers
reach for a monkey patch as their tool of first resort, *even when a
simpler, more traditional solution is possible*."

So true. Here are a couple cases I can think of people doing "monkey
patching" and the alternative traditional solution:

* adding new (or perceived missing) functionality (methods) to a class. The
traditional solution would be to just inherit from the class and use the
derived class instead where you want this new functionality. Since you
can't inherit from some classes (i.e. immediates, a problem with the
language IMHO), you can instead use something like Forwardable instead.

* adding #to_* methods to String. A single letter is quite common for the *
which can make a collision all the more likely. The more encapsulated
solution would be to class method for creating one of these objects from a
String (i.e. klass#from_s(s)).

Every case I thought that I needed "monkey patching", I've found a
relatively simple solution. I usually only do monkey patching in the
following cases which have no reuse: top-level script, testing, and quick
hacking.

Eric

Avdi Grimm

unread,
Feb 23, 2008, 5:36:58 PM2/23/08
to
On Sat, Feb 23, 2008 at 5:23 PM, Eric Mahurin <eric.m...@gmail.com> wrote:
> I don't agree with the title

Like I said at the beginning of the article, neither do I ;-)

> * adding new (or perceived missing) functionality (methods) to a class. The
> traditional solution would be to just inherit from the class and use the
> derived class instead where you want this new functionality. Since you
> can't inherit from some classes (i.e. immediates, a problem with the
> language IMHO), you can instead use something like Forwardable instead.

Indeed. The irony here is that Ruby is perhaps the easiest language
in the world to implement delegation in. I'm planning on writing a
series of posts on alternatives to monkey patching, and delegation is
going to be one of the first techniques I talk about.

> Every case I thought that I needed "monkey patching", I've found a
> relatively simple solution. I usually only do monkey patching in the
> following cases which have no reuse: top-level script, testing, and quick
> hacking.

Quite. I have no objection to monkey patching in those contexts,
assuming that it really IS the easiest solution.

Thanks for the reply!

--
Avdi

Eric Mahurin

unread,
Feb 23, 2008, 6:27:02 PM2/23/08
to
[Note: parts of this message were removed to make it a legal post.]

On Sat, Feb 23, 2008 at 4:36 PM, Avdi Grimm <av...@avdi.org> wrote:

> On Sat, Feb 23, 2008 at 5:23 PM, Eric Mahurin <eric.m...@gmail.com>
> wrote:
> > * adding new (or perceived missing) functionality (methods) to a class.
> The
> > traditional solution would be to just inherit from the class and use
> the
> > derived class instead where you want this new functionality. Since you
> > can't inherit from some classes (i.e. immediates, a problem with the
> > language IMHO), you can instead use something like Forwardable instead.
>
> Indeed. The irony here is that Ruby is perhaps the easiest language
> in the world to implement delegation in. I'm planning on writing a
> series of posts on alternatives to monkey patching, and delegation is
> going to be one of the first techniques I talk about.
>

Here are the main alternatives I use (in order):

* put the functionality elsewhere. The simplest example is instead of
monkey-patching String#to_xyz, make XYZ::from_s. When your new class wants
some interaction with a built-in class, put the functionality in the new
class instead of monkey-patching it into built-in class. The monkey
patching approach usually just saves you a few characters when using the new
functionality. I do this 95% of the time where others might monkey-patch.
* inherit the class where you want additional functionality and use the
derived class instead.
* use delegation if inheritance doesn't work (immediates). Delegation is
basically just a "has-a" implementation of "is-a" (inheritance), but it
gives a little more flexibility. I've never really had to use this when I
was tempted to monkey-patch.

It would be an interesting exercise to go through some of the ruby stdlib
and show alternatives to monkey-patching.

Eric

Thomas Hurst

unread,
Feb 23, 2008, 6:51:32 PM2/23/08
to
* Eric Mahurin (eric.m...@gmail.com) wrote:

> I believe that "monkey patching" in packages can easily kill
> interoperability with other packages.

Anyone remember the Chainsaw Infanticide Logger Manuever? ActiveSupport
hacked into logger.rb to remove formatting, which was really nice when
you wanted to use ActiveRecord in something outside Rails.

And let's not mention the scary hacking of require. Let's just say.. I
don't use Active* in any of my !Rails projects any more.

--
Thomas 'Freaky' Hurst
http://hur.st/

M. Edward (Ed) Borasky

unread,
Feb 23, 2008, 6:56:14 PM2/23/08
to
Avdi Grimm wrote:
> Hi folks,
>
> I wrote a blog post with the intentionally provocative title above,
> which can be found here:
>
> http://avdi.org/devblog/?p=18
>
> While the title is a bit of deliberate hyperbole, I am genuinely
> troubled about the popularization of monkey patching in the Ruby
> community. I explain my reasons more thoroughly in the post, but
> here's a synopsis:
>
> Monkeypatching has become the hip thing to do in the
> Ruby and (especially?) Rails communities, and it has
> reached the point where experienced programmers are
> turning to it as the tool of first resort *even* when there
> is a simpler, more traditional solution available. I
> suggest that it's time for Ruby hackers to start setting a
> better example.
>
> My hope with this post is to start a conversation about fostering
> robust software extension mechanisms in the Ruby ecosystem. I welcome
> any comments, both here and on the blog.
>

One of my friends once passed this little quotation on to me:

"Always code as if the person who will maintain your code is a violent
psychopath who knows where you live."

Marc Heiler

unread,
Feb 23, 2008, 7:13:49 PM2/23/08
to
Rails != Ruby

The same is valid for the communities. The communities only partially
overlap.
I know many that do not use rails.
I know many that do use rails.

It is frustrating to try to read a blog that claims monkey patching is
destroying ruby when in actuality the author meant Rails. And I do not
care about rails either way (positive or negative) so it hardly
interests me ...
--
Posted via http://www.ruby-forum.com/.

Avdi Grimm

unread,
Feb 23, 2008, 7:26:31 PM2/23/08
to
On Sat, Feb 23, 2008 at 7:13 PM, Marc Heiler <shev...@linuxmail.org> wrote:
> It is frustrating to try to read a blog that claims monkey patching is
> destroying ruby when in actuality the author meant Rails.

No, I meant ruby. I have been coding in Ruby for ~7 years, since long
before Rails appeared. At work I'm the first to correct people when
they make a comment about "Ruby" when they really are talking about a
Rails-specific feature.

Yes, I used a Rails example. And I suspect that it's true that the
phenomenon is more prevalent in in the Rails community than in the
wider Ruby community. But for better or worse the majority of Ruby
code being written today is being written for Rails, and the Ruby
coders of tomorrow are cutting their teeth in the Rails community.
Rails cultural problems will, increasingly, be Ruby cultural
problems.

--
Avdi

Radosław Bułat

unread,
Feb 23, 2008, 8:04:27 PM2/23/08
to
I can say that I agree with all pieces of your article. This issue is
not related to rails community, it's ruby programmers issue (but of
course there are programmers that not make such a mistakes). The same
goes with using modules as mixins when there should be used delegation
or inheritance and many other things. I say that Ruby is very sharp
knife. It's very powerful but you must know how to operate with it to
not hurt yourself.


--
Radosław Bułat

http://radarek.jogger.pl - mój blog

Morton Goldberg

unread,
Feb 23, 2008, 8:34:03 PM2/23/08
to
On Feb 23, 2008, at 6:56 PM, M. Edward (Ed) Borasky wrote:

> One of my friends once passed this little quotation on to me:
>
> "Always code as if the person who will maintain your code is a
> violent psychopath who knows where you live."


Truly wonderful. If there were a poster of that available, I'd buy it
and hang it where I could see it when I look up from my screen.

You didn't make an attribution, so I presume you don't know who
originated it. Too bad.

Regards, Morton

Trans

unread,
Feb 23, 2008, 9:08:58 PM2/23/08
to
Oh bother. If it ain't the Duck, it's the Monkey.

No. It's not the Monkey, or the Duck that's killing Ruby... It's the
Peoples.

T.

Todd Benson

unread,
Feb 23, 2008, 9:21:25 PM2/23/08
to

In other words, it's the hairless monkeys (I'm one of them :).

Todd

Phlip

unread,
Feb 23, 2008, 9:43:50 PM2/23/08
to
> http://avdi.org/devblog/?p=18

> Monkeypatching has become the hip thing to do in the
> Ruby and (especially?) Rails communities, and it has
> reached the point where experienced programmers are
> turning to it as the tool of first resort *even* when there
> is a simpler, more traditional solution available. I
> suggest that it's time for Ruby hackers to start setting a
> better example.

I don't know what "Aspect Oriented Programming" (and please don't try the
standard explanations - they don't work on me, any more than "OO is about
modeling the Real World in objects...").

I want this:

module MyModule
class ::String
def inspect
return 'shock the monkey'
end
end
end

I want .inspect, or whatever, outside my module, to behave normally. But if
you inspect a string while my module is above you on the call stack, I get
my hotwired version of .inspect.

Does anyone have a Ruby Hack which does that yet? How hard would it be?

--
Phlip
http://assert2.rubyforge.org/


Avdi Grimm

unread,
Feb 23, 2008, 9:50:14 PM2/23/08
to
On Sat, Feb 23, 2008 at 9:08 PM, Trans <tran...@gmail.com> wrote:
> No. It's not the Monkey, or the Duck that's killing Ruby... It's the

My point exactly :-)

--
Avdi

Joel VanderWerf

unread,
Feb 23, 2008, 10:09:54 PM2/23/08
to

We've survived worse. Remember the Snail?

http://blade.nagaokaut.ac.jp/cgi-bin/vframe.rb/ruby/ruby-talk/20717?20588-22393

--
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Morton Goldberg

unread,
Feb 23, 2008, 10:12:21 PM2/23/08
to

No, no, it's the apes. Monkeys have tails. The tailless primates are
called apes.

Regards, Morton

M. Edward (Ed) Borasky

unread,
Feb 23, 2008, 10:26:10 PM2/23/08
to
Right -- I don't know who originated it, but I'm guessing you could find
some guesses on Wikipedia. :)

I do know that Gerry Weinberg is the originator of "If we built our
buildings the same way we build software, the first woodpecker that came
along would destroy civilization."

Phlip

unread,
Feb 23, 2008, 10:28:24 PM2/23/08
to
Morton Goldberg wrote:

> No, no, it's the apes. Monkeys have tails. The tailless primates are
> called apes.

Didn't someone once identify the Common Patcher Monkey species as /Monachus
recarcio/?

(The one that feeds on bugs, marketects, and Starbucks pastries?)

--
Phlip


James Britt

unread,
Feb 24, 2008, 1:06:02 AM2/24/08
to
Avdi Grimm wrote:
> Hi folks,
>
> I wrote a blog post with the intentionally provocative title above,
> which can be found here:
>
> http://avdi.org/devblog/?p=18
>
> While the title is a bit of deliberate hyperbole, I am genuinely
> troubled about the popularization of monkey patching in the Ruby
> community.

That so many people use the phrase "monkey patching" suggests many
people don't actually understand how to use it.

It's no more "patching" than reassigning to a variable is patching.

"ZOMG! You're changing something at runtime!"

Yeah, happens all the time. Use with caution; get on with life.

Maybe if people weren't so spooked by metaprogramming they'd see it as
yet one more feature of the language and use it appropriately, rather
than treating it like high-priest voodoo that seemingly works by magic.

--
James Britt

"Serious engineering is only a few thousand years old. Our attempts at
deliberately producing very complex robust systems are immature at best."
- Gerald Jay Sussman

Phlip

unread,
Feb 24, 2008, 2:13:31 AM2/24/08
to
James Britt wrote:

> It's no more "patching" than reassigning to a variable is patching.
>
> "ZOMG! You're changing something at runtime!"

That's not MP. MP is changing a published class by re-writing one of its
existing methods. Your whole program and all its modules get the new
version, at design time.

Otherwise, you have to...

- inherit that class
- override the method
- upgrade all the class objects' .new sites

The last one is the reason - without pristine Construction Encapsulation -
MP is the shortest path between two points.

So when we "use with caution", where highly popular libraries - obvious
example Rails - get to patch whatever they feel like, and modules below them
in the pecking order must refrain from patching so freely.

That's why I suggested encapsulating the patch effects to the patching
module. That's either a new feature in Ruby, or a very clever
metaprogramming hack. Problem solved.

--
Phlip


Eric Mahurin

unread,
Feb 24, 2008, 3:31:30 AM2/24/08
to
[Note: parts of this message were removed to make it a legal post.]

On Sun, Feb 24, 2008 at 12:06 AM, James Britt <james...@gmail.com> wrote:

> Avdi Grimm wrote:
> > Hi folks,
> >
> > I wrote a blog post with the intentionally provocative title above,
> > which can be found here:
> >
> > http://avdi.org/devblog/?p=18
> >
> > While the title is a bit of deliberate hyperbole, I am genuinely
> > troubled about the popularization of monkey patching in the Ruby
> > community.
>
> That so many people use the phrase "monkey patching" suggests many
> people don't actually understand how to use it.
>
> It's no more "patching" than reassigning to a variable is patching.


When you are talking about global (and to a certain extent class) variables,
there is an analogy. Most languages do have global variables, but they are
also usually discouraged (especially changing them) because of the
side-effects (state changes). Monkey patching is in this same vein, except
worse IMHO (the state changes can be more intrusive).

Like global variables, I don't think monkey patching is a good practice for
reusable, inter-operable, and maintainable code.

On the other hand, one nice time to use it is for creating a ruby-based
DSL. But, when making a DSL where monkey-patching helps, I think the monkey
patching should be done as a thin layer. The base functionality should use
no monkey-patching so that it can be used cleanly with other packages.
You'd likely have problems combining multiple monkey-patched DSLs together
if you couldn't disable at least some of the monkey-patching.

You might also say the same of global variables. If you use them, use them
only at the highest user/DSL/script/test level. The baseline reusable
functionality should just be passed that global variables and not use them
directly.

Eric

ThoML

unread,
Feb 24, 2008, 3:42:16 AM2/24/08
to
> I want this:
>
> module MyModule
> class ::String
> def inspect
> return 'shock the monkey'
> end
> end
> end
>
> I want .inspect, or whatever, outside my module, to behave normally.

If ruby had a package/module system with import/export where constants
could be renamed and assigned for a specific set of code ... well.
Such a system would be tricky to manage though due to all classes
being open. Nothing stops you from adding a new method later on and it
could sometimes be difficult (or rather non-intuitive) to determine
whether the class X in that method should be the real class X or class
Y that was assigned to X in the import statement of such a module.

Anyway, you could also rewrite (live/hot/monkey patch, whoahoo!)
String#inspect to check if the caller belongs to your module. If I'm
not mistaken, ruby19 provides means to detect who/what is calling a
method.

I'd rather subclass String though, since this special use should be
restricted to a well-defined module.

But what should happen in your proposal if a method returns such a
special string and something outside the module calls inspect?

BTW I don't think the python community originally frowned upon MP. I
can remember a self-proclaimed python expert who once explained with
sparkling eyes the merits of MP to a young newcomer. I cannot remember
the slightest trace of doubt and this already happened a few years
ago.

Regards,
Thomas.

Robert Klemme

unread,
Feb 24, 2008, 4:39:29 AM2/24/08
to
On 23.02.2008 23:36, Avdi Grimm wrote:
> On Sat, Feb 23, 2008 at 5:23 PM, Eric Mahurin <eric.m...@gmail.com> wrote:
>> I don't agree with the title
>
> Like I said at the beginning of the article, neither do I ;-)
>
>> * adding new (or perceived missing) functionality (methods) to a class. The
>> traditional solution would be to just inherit from the class and use the
>> derived class instead where you want this new functionality. Since you
>> can't inherit from some classes (i.e. immediates, a problem with the
>> language IMHO), you can instead use something like Forwardable instead.
>
> Indeed. The irony here is that Ruby is perhaps the easiest language
> in the world to implement delegation in. I'm planning on writing a
> series of posts on alternatives to monkey patching, and delegation is
> going to be one of the first techniques I talk about.

But keep in mind that since it's so easy you can shoot yourself in the
foot equally well as I have tried to point out in a recent post:
http://groups.google.com/group/comp.lang.ruby/msg/90f76656fd2c0f68

On a broader scale: I agree with your assessment that MP can cause bugs
that are hard to find and that there are usually other ways to achieve
the same effect in cleaner ways. I for my part try to steer people away
from using those "dirty" techniques (MP, inheriting core classes etc.)
whenever I think there is a easier and clearer solution available.

Do we need a discussion about this? Is MP really destroying Ruby and /
or Rails? I don't know. Maybe MP is just the current buzz word that
everybody uses and will go away like any other fashion. But I do think
that it's helpful to once in a while step out of daily business and
think about things on a broader scale. It helps keep our minds flexible
and not run into a completely wrong direction for too long a time.

Kind regards

robert

Robert Dober

unread,
Feb 24, 2008, 5:46:31 AM2/24/08
to

I really think that your BLOG entry is a bad way to say something
intelligent, AMOF you say many intelligent things.

It would make so much more sense to explain aspects of the technique
you do not like, I see the following issues:

Lots of people seem to confuse Runtime class modification
(metaprogramming) with MP.
There are very important issues to be discussed about if MP is on core
classes or commonly used packages
and most importantly if you MP in a package or in an application.

I have the feeling that you were making *very valid* points but they
do not concern MP in at least 50% of their use cases.
(or maybe those I use).

As others have said it somehow boils down to bad code vs. good code
and thats why I would have appreciated some examples of everyday code.
It is obvious that doing things like
class Array
def size; 0 end
end
in a library or an application is nonsense.
OTOH
class Array
def to_hash
Hash[*self.flatten]
end
end
might just make an application much more readable, but I still would
think twice of putting it into a library.
If I do so (putting it into a library ) another point you have been
talking about becomes important, convention, documentation.
Your Blog post could be a series of very interesting posts but you are
throwing years of experience and reflexion at us in one single post.
Have mercy with us !

But do not fear I am working on a programming language that will not
allow for bad code anymore, first release is scheduled for stardate
4242.42 ;)

Cheers
Robert

--
http://ruby-smalltalk.blogspot.com/

---
Whereof one cannot speak, thereof one must be silent.
Ludwig Wittgenstein

Mikel Lindsaar

unread,
Feb 24, 2008, 8:23:15 AM2/24/08
to


In the para phrased great words of Mel Blanc:

"Duck season!"
"Monkey season!"
"Duck season!"
"Monkey season!"
"Monkey season!"
"Duck season! FIRE!!!"

<BLAM>

http://en.wikipedia.org/wiki/Rabbit_Fire


Regards,

Mikel
http://lindsaar.net/

Avdi Grimm

unread,
Feb 24, 2008, 9:50:19 AM2/24/08
to
On Sun, Feb 24, 2008 at 5:46 AM, Robert Dober <robert...@gmail.com> wrote:
> As others have said it somehow boils down to bad code vs. good code
> and thats why I would have appreciated some examples of everyday code.

Point taken. I'm planning a series of posts on approaches to dynamic
class modification in which I will be using concrete code examples.
So stay tuned, and hopefully things will become clearer.

--
Avdi

Kevin Williams

unread,
Feb 24, 2008, 10:36:54 AM2/24/08
to
James Britt wrote:
> Yeah, happens all the time. Use with caution; get on with life.

I agree with everything Avdi has said, with the caveat that James is
also right here. Use with caution, document the crap out of any
monkeypatching you do, and get on with life.

Bob Hutchison

unread,
Feb 24, 2008, 11:17:23 AM2/24/08
to

On 23-Feb-08, at 5:36 PM, Avdi Grimm wrote:

> On Sat, Feb 23, 2008 at 5:23 PM, Eric Mahurin
> <eric.m...@gmail.com> wrote:
>>

>> * adding new (or perceived missing) functionality (methods) to a
>> class. The
>> traditional solution would be to just inherit from the class and
>> use the
>> derived class instead where you want this new functionality. Since
>> you
>> can't inherit from some classes (i.e. immediates, a problem with the
>> language IMHO), you can instead use something like Forwardable
>> instead.
>
> Indeed. The irony here is that Ruby is perhaps the easiest language
> in the world to implement delegation in. I'm planning on writing a
> series of posts on alternatives to monkey patching, and delegation is
> going to be one of the first techniques I talk about.

Okay, let's be a little bit careful here. There are at least two
distinct meanings of 'delegate' in the OO world and people seem to
flip between them in the same paragraph, even sentence. The seemingly
most common use is as a synonym for 'forwarding' which is the design
pattern where a second object provides the implementation of a missing
method. The original use was as an alternative to inheritance, it's a
lot like the other meaning but with the crucial difference that 'self'
is the first object not the second (so if you call a method or use an
instance variable in the delegated implementation the first object is
checked not the second).

Unless there's something in Ruby that I don't know about then the
inheritance-equivalent use is not so easily implemented in Ruby. The
effect of monkey patching is more like this meaning of 'delegation'
than it is to the design pattern (in fact, I tend to think of MP as a
kind of inheritance).

Anyway...

MP is a very powerful technique. Powerful techniques are open to
abuse, very powerful even more so.

So how do you constrain power? Well you can restrict its use trying to
prevent abuse at the cost of interfering with perfectly valid uses. Or
you can make it as general as possible leaving the possibility of
abuse completely unrestricted, but at the same time leaving the valid
uses as unrestricted as possible.

This is kind of like the arguments around static typing. If this
analogy holds, then Ruby has already expressed its position. Dynamic
languages in general have expressed their positions.

Personally, I like dynamic languages.

Ruby isn't alone in this. Python has come up already. But there are
other languages that do this, including Smalltalk and Common Lisp/CLOS.

What I think would be nice in Ruby is that the warning flag (-w) would
go a little further and warn the programmer when a class is reopened
(and where).

Aside from that, there isn't a lot to argue with in your blog posting.
Your points individually are fine and quibbling over insignificant
details on a mailing list is a waste of time (though it might be ideal
in a pub :-) In other words, I don't disagree with anything you say
until you start drawing conclusions. I *like* monkey patching and I
approve of its proper use. Furthermore, I don't special case the abuse
of MP, it is just like any other abuse of a feature: bad.

Cheers,
Bob


----
Bob Hutchison -- tumblelog at http://www.recursive.ca/so/
Recursive Design Inc. -- weblog at http://www.recursive.ca/hutch
http://www.recursive.ca/ -- works on http://www.raconteur.info/cms-for-static-content/home/

Avdi Grimm

unread,
Feb 24, 2008, 11:18:24 AM2/24/08
to
On Sun, Feb 24, 2008 at 10:36 AM, Kevin Williams <kev...@gmail.com> wrote:
> I agree with everything Avdi has said, with the caveat that James is
> also right here. Use with caution, document the crap out of any
> monkeypatching you do, and get on with life.

The "use with caution" part is key. All hyperbole aside, I'm not
saying we should never monkey patch. I'm just concerned when I see it
used by smart programmers as if it were the standard Ruby mechanism of
extension.

--
Avdi

Avdi Grimm

unread,
Feb 24, 2008, 11:24:22 AM2/24/08
to
On Sun, Feb 24, 2008 at 11:17 AM, Bob Hutchison <hu...@recursive.ca> wrote:
> Aside from that, there isn't a lot to argue with in your blog posting.
> Your points individually are fine and quibbling over insignificant
> details on a mailing list is a waste of time (though it might be ideal
> in a pub :-) In other words, I don't disagree with anything you say
> until you start drawing conclusions. I *like* monkey patching and I
> approve of its proper use. Furthermore, I don't special case the abuse
> of MP, it is just like any other abuse of a feature: bad.

Thanks. I think the reason I'm making a special case of monkey
patching is that, at least in some subsets of the community, I'm
seeing it morph into almost a standard extension technique. How do
you extend ActiveRecord::Base? Why, you re-open it, of course!
That's how everyone does it!

This could be more of a Rails thing at the moment, but as I commented
earlier, Rails culture will increasingly become Ruby culture, because
that's where the new Ruby programmers are coming from.

--
Avdi

Jari Williamsson

unread,
Feb 24, 2008, 11:49:31 AM2/24/08
to
As a comparison, the "Design Patterns in Ruby" by Russ Olsen (where MP
is one of the Ruby design patterns, in addition to the standard GoF
patterns) never suggests reopening classes as a solution to any problem
in the book, as far as I remember. When needed, methods are added on a
per-object level.

And David Black seem to say about the same thing as the OPs blog, look
at page 28 in this presentation:
http://www.chariotsolutions.com/slides/pdfs/rubyeast2007-black-PerObjectBehavior.pdf


Best regards,

Jari Williamsson

Trans

unread,
Feb 24, 2008, 11:54:20 AM2/24/08
to

On Feb 24, 11:24 am, "Avdi Grimm" <a...@avdi.org> wrote:
> On Sun, Feb 24, 2008 at 11:17 AM, Bob Hutchison <hu...@recursive.ca> wrote:
> > Aside from that, there isn't a lot to argue with in your blog posting.
> > Your points individually are fine and quibbling over insignificant
> > details on a mailing list is a waste of time (though it might be ideal
> > in a pub :-) In other words, I don't disagree with anything you say
> > until you start drawing conclusions. I *like* monkey patching and I
> > approve of its proper use. Furthermore, I don't special case the abuse
> > of MP, it is just like any other abuse of a feature: bad.
>
> Thanks. I think the reason I'm making a special case of monkey
> patching is that, at least in some subsets of the community, I'm
> seeing it morph into almost a standard extension technique. How do
> you extend ActiveRecord::Base? Why, you re-open it, of course!
> That's how everyone does it!

This whole point could be moot if each library could have it's own
rendition of (core) classes/modules.

Then with two types of require: one simply to call on a library and
another to fully integrate a library, extensions and all, then we
would have full control over the whole MP affair.

Yes, we can have our cake and eat it too! But it's up to Matz to be
our Marie.

T.

Bob Hutchison

unread,
Feb 24, 2008, 12:07:30 PM2/24/08
to

On 24-Feb-08, at 11:24 AM, Avdi Grimm wrote:

> On Sun, Feb 24, 2008 at 11:17 AM, Bob Hutchison <hu...@recursive.ca>
> wrote:
>> Aside from that, there isn't a lot to argue with in your blog
>> posting.
>> Your points individually are fine and quibbling over insignificant
>> details on a mailing list is a waste of time (though it might be
>> ideal
>> in a pub :-) In other words, I don't disagree with anything you say
>> until you start drawing conclusions. I *like* monkey patching and I
>> approve of its proper use. Furthermore, I don't special case the
>> abuse
>> of MP, it is just like any other abuse of a feature: bad.
>
> Thanks. I think the reason I'm making a special case of monkey
> patching is that, at least in some subsets of the community, I'm
> seeing it morph into almost a standard extension technique. How do
> you extend ActiveRecord::Base? Why, you re-open it, of course!
> That's how everyone does it!

An analogy maybe... it can be remarkably difficult to get new
programmers to use composition rather than inheritance. This is dealt
with through education (occasionally a brutal education :-)

Monkey patching *is* a standard extension technique. It isn't just a
hack. At least, that's what I say :-) If you design a class that is to
be used in different contexts then it is reasonable to assume that the
class's responsibilities may change with context. This change in
responsibility may not be reflected precisely by either inheritance or
composition (or forwarding) -- inheritance and composition may be
something of a contortion. You can make a pretty strong argument that
you shouldn't be abusing inheritance or composition to avoid something
neatly expressed by MP. Of course someone can use this interpretation
of MP to justify a lot of dubious stuff.

Ruby has other techniques that are not so much talked about that can
deal with some of the suspicious uses of MP. These come to mind
immediately: dynamically including modules into a class or specific
*object* (there are some handy hooks defined in Ruby that allow some
really nice stuff to be done when this happens), and methods defined
on specific *objects*. These are open to abuse too, and can be
spectacularly difficult to debug if you are thinking that an object is
defined by its class.

>
>
> This could be more of a Rails thing at the moment, but as I commented
> earlier, Rails culture will increasingly become Ruby culture, because
> that's where the new Ruby programmers are coming from.

I agree I think. I believe that it is very important to distinguish
between a language's capability to do something and its use/abuse. The
trouble with Rails, and its tremendous success, is that less
experienced programmers can get a *long* way before they really need
to know anything about programming. Somewhere in that interval is room
for some pretty ugly code -- it isn't just MP.

Cheers,
Bob

>
>
> --
> Avdi

Eric Mahurin

unread,
Feb 24, 2008, 12:13:33 PM2/24/08
to
[Note: parts of this message were removed to make it a legal post.]

On Sun, Feb 24, 2008 at 4:46 AM, Robert Dober <robert...@gmail.com>
wrote:

> On Sat, Feb 23, 2008 at 10:07 PM, Avdi Grimm <av...@avdi.org> wrote:
> > http://avdi.org/devblog/?p=18


>
> Lots of people seem to confuse Runtime class modification
> (metaprogramming) with MP.
> There are very important issues to be discussed about if MP is on core
> classes or commonly used packages
> and most importantly if you MP in a package or in an application.
>
> I have the feeling that you were making *very valid* points but they
> do not concern MP in at least 50% of their use cases.
> (or maybe those I use).
>

This blog is really only an attack on the popularity of "monkey patching"
(the python definition - patching existing classes/methods), not all of
meta-programming:

http://en.wikipedia.org/wiki/Monkey_patch

If done with care the other aspects of meta-programming don't prevent
portable/reusable/inter-operable code:

* modifying methods of a specific object (unless it is a "global") at
run-time.
* evaling a piece of dynamically generated code.
* defining classes on the fly (class factory)
* introspection
* etc.

In my opinion, people should think about monkey-patching like they do global
variables. Monkey-patching should be discouraged like global variables are.

James Tucker

unread,
Feb 24, 2008, 12:27:12 PM2/24/08
to

I can't agree with this, there's too much going on to really make such
a widely aimed statement. Monkey patching may be destroying a lot of
developers, but how can most of 'the community' who, (myself
included), have not been involved with ruby for sufficient years to be
entirely confident on which patterns will be bad and which will be
good, for a given situation. With the amount I have learned about ruby
over the past couple of years, and the drastic swings in code quality,
I can see how these things happen too. I went through stages of
enjoying meta based solutions, right back to OO again, learning the
simultaneous destruction and power of various techniques. I've been
through stages of writing code that very few people can read, and
those that can don't want to, right back to making code that non-
programmers can read clearly. Ruby makes all sides easy, what you
choose is a combination of culture, purpose, desire and habit. Many
young ruby developers have a desire to be 'clever', and this often
starts to disappear after some experience (in my experience). Hail
simplicity, it will be good for all of us, but as for monkey patching
destroying ruby, I'm not so sure.

Trying to stay a little away from the pattern discussion (as I hate
the term, I think it leads to mis(/over)use). I would make the
observation that some pieces of software in use in some really
successful ruby projects (one that really screams out in my head, as
rails was mentioned, is evented_mongrel, by Kirk Haines), is supplied
entirely as a monkey patch along with the swiftiply package.

The important thing is for developers to realize the impact of the
code they write, and as most experienced developers can tell you, this
takes wisdom that is gained largely through experience, and one can
never expect to catch everything in every scenario. The 'pattern' (if
you like) of monkey patching is not one which is easy to maintain, by
it's nature it can be very coupled with any underlying implementation,
and often requires shortcuts to be taken (some (maybe most) would say
it is a shortcut by it's very nature).

It is however, a fantastic prototyping tool. It is incredible when
used at the final application development stage when you really just
need a behavior to change on an underlying framework or api. Clearly
there are better and worse ways to go about these things, and as
always tests and documentation really help (as by these procedures, if
there is a better way, you will often find it producing those). I
think for frameworks under ruby, there are possibly some 'patterns'
which are good to adhere to, and they are being discussed continually
all over the place. Mostly they boil down to good (clean, maybe so far
as to say 'pure') OO patterns, for which ruby provides some real
convenience.

$0.02

Phlip

unread,
Feb 24, 2008, 12:36:59 PM2/24/08
to
> I can't agree with this, there's too much going on to really make such
> a widely aimed statement.

Saying MP is destroying Ruby is like saying the Ediacaran Radiation
destroyed life.

It did - it destroyed all the body-plans that weren't working!

MP is natural selection in action. Today's MP is tomorrow's patch to the
core.

Christopher Dicely

unread,
Feb 24, 2008, 12:57:59 PM2/24/08
to

The thing is, it is *a* standard Ruby mechanism of extension, and it
may often be the simplest--for them, even when it doesn't seem to be
for you. And that's the tricky thing about simplicity; its mostly not
objective, its mostly about what matches the way a given person
thinks. The upside of Ruby's embrace of "there's more than one way to
do it" is that there is likely to be a way available that fits the way
you think fairly naturally, no matter where you come to Ruby from and
how long you've been using it (as long as you've mastered the basics).
The downside is that the most simple, direct, and natural way for
someone else to do something in Ruby may not be the most simple,
direct, and natural way for you.

That being said, the hyperbolic title aside, your blog post seems to
be largely stuff I can agree with, though I think you've misplaced the
problem very slightly. I don't think monkey patching itself is a
problem, I think the problem is that there isn't a good enough body of
experience of what to do and what not to do with monkey patching.
(Both in terms of when monkey patching is the right solution and when
there is a better alternative, and what to do and avoid doing when
you've made the decision to monkey patch.) Unlike basic composition
vs. inheritance questions, and other OOP considerations where the
facilities have been common in industrially-popular languages for
quite some time and, even if there aren't cut-and-dried standards to
apply there is a considerable body of advice and experience that most
programmer's have been exposed to, monkey patching is a lot more of a
"wild frontier" right now.

But criticism like yours is an important part of the dialogue that
needs to happen to work out where the problems are and to file the
rough edges off so that monkey patching can become a well-understood
tool that can be used effectively where it is appropriate and avoided
where it is not.

furtiv...@gmail.com

unread,
Feb 24, 2008, 3:50:35 PM2/24/08
to

The problem is not monkey patching itself, but that there is no
unified mechanism for dealing with it. We wish to make local changes
to (what is currently implemented as) global objects, namely the
singletons comprising the built-in classes. That's difficult or
impossible to do cleanly.

Is (or was) there a serious plan for something like selector
namespaces in ruby 2.0? I found http://rubygarden.org/ruby/page/show/Rite
which appears to be down (google cache:
http://64.233.169.104/search?q=cache:ej4aPcNY41QJ:rubygarden.org/ruby/page/show/Rite+http://rubygarden.org/ruby/page/show/Rite&hl=en&ct=clnk&cd=1&gl=us
)

I have a simple example from my own experience. In one project I had
a bewildering number of property sets which needed to be added,
subtracted, or'd, and and'ed with each other every which way. I began
using a Set class but it quickly became too cumbersome, as many of my
definitions used hash literals. Inserting +,-,&,| methods into the
Hash class was a tremendous help: using these operations with Hash
literals GREATLY improved readability and maintainability.

Now what if I made my project into a library for others to use? I
want MY Hash in MY library ONLY, without affecting the client. I
MIGHT be able to scope the change to Hash appropriately, for example
by taking a snapshot of Hash then restoring it before returning to the
client. But eventually I'll run into a case where I need to yield to
client code while at the same needing MY Hash class. Thus I'll be
forced to pollute the client with my funky Hash.

--FC

Gary Wright

unread,
Feb 24, 2008, 4:43:36 PM2/24/08
to

On Feb 24, 2008, at 3:54 PM, furtiv...@gmail.com wrote:
> I have a simple example from my own experience. In one project I had
> a bewildering number of property sets which needed to be added,
> subtracted, or'd, and and'ed with each other every which way. I began
> using a Set class but it quickly became too cumbersome, as many of my
> definitions used hash literals. Inserting +,-,&,| methods into the
> Hash class was a tremendous help: using these operations with Hash
> literals GREATLY improved readability and maintainability.

You describe one leading cause of monkeypatching--missing
functionality in the core classes.
Here is another example:

class Object
def singleton_class # or meta_class or eigen_class or ...
(class <<self; self; end)
end
end

Matz & company have done a great job tending to the core classes but
there are idioms in the wild that are not yet incorporated into the
'official' releases.

I know of two ad-hoc attempts to organize common library idioms:
Facets and Rails ActiveSupport, there are probably others. But even
these attempts are problematic:

Facets defines Hash#- based on [key,value] pairs and not keys. An
argument can be made for either approach but you can't integrate code
bases that have different expectations for Hash#-.
Active Support defines Array#in_groups_of, which is close to
Enumerator#each_slice but not quite the same.

There is a tension between the timely incorporation of idioms into
the standard distribution and maintaining some overall architectural
structure to the libraries. Some idioms just won't fit.


Gary Wright

Clifford Heath

unread,
Feb 24, 2008, 6:19:32 PM2/24/08
to
Phlip wrote:
>> http://avdi.org/devblog/?p=18
> I don't know what "Aspect Oriented Programming"....

> I want this:
(clip)
> I want .inspect, or whatever, outside my module, to behave normally. But if
> you inspect a string while my module is above you on the call stack, I get
> my hotwired version of .inspect.
> Does anyone have a Ruby Hack which does that yet? How hard would it be?

It can't be done in Ruby. I spent quite a lot of time analysing how to
construct such a language, as I've used this kind of design principle
for more than a decade to design aspect-oriented object models.

The problem is that for every call, you need to pass in a hidden parameter
which contains a descriptor for every namespace visible from the caller's
perspective, and you need to use that list of namespaces to disambiguate
the method call itself. Access to other parameters of the method from
inside the callee is also a problem, as they may be of classes that "don't
exist" from the POV of the callee.

Basically, such a language is possible, but I don't believe the implementation
can be made efficient.

A more restricted version of this behaviour can be done by treating every
aspect-limited extension (which I call a facet) of an object, as a special
kind of subclass. Such a subclass must not be allowed private access; it
can only use the public interface of its superclass. The superclass instance
is initially instantiated as just the superclass, but the facet methods are
"realized" as they're used, revealing the aspect behaviour of the object.
Again, this can't be faked very well in Ruby, and the various Traits modules
are a better solution.

However, I do believe that from a modeling POV, the approach is very valuable.
My ActiveFacts project explores the only real way to do this effectively,
which is in terms of elementary fact types. That means that all roles of
each object type are specified in one or more vocabularies (aspects), and
since the fact types are *elementary*, they're totally composable.

The same approach isn't easy to extend to modeling behaviour, for the
reasons I mentioned. You say tomato, I say tomatoe, but in Ruby, the
composition of the two things can only have one name, or you get collisions.
Unless you want to modify a Ruby interpreter to allow you to monkey-patch
Method#call, but then you're implementing your own VM :-).

Clifford Heath.

Phlip

unread,
Feb 24, 2008, 10:34:43 PM2/24/08
to
Clifford Heath wrote:

>> I want .inspect, or whatever, outside my module, to behave normally. But
>> if you inspect a string while my module is above you on the call stack, I
>> get my hotwired version of .inspect.
>> Does anyone have a Ruby Hack which does that yet? How hard would it be?
>
> It can't be done in Ruby.

Could we patch the core interpreter to add the ability?

> I spent quite a lot of time analysing how to
> construct such a language, as I've used this kind of design principle
> for more than a decade to design aspect-oriented object models.

So I'm right about my guess - that magic is the root principle of AOP.

(If so, someone could have told me that already, instead of just reading the
AOP tourist's brochure to me!;)

If so, and if it "can't be done in Ruby", why are there Ruby gems that talk
about AOP?

> A more restricted version of this behaviour can be done by treating every
> aspect-limited extension (which I call a facet) of an object, as a special
> kind of subclass.

That's probably the Ruby AOP packages. Thanks for the pointers!

--
Phlip


James Gray

unread,
Feb 24, 2008, 11:02:28 PM2/24/08
to
On Feb 23, 2008, at 4:23 PM, Eric Mahurin wrote:

> On Sat, Feb 23, 2008 at 3:07 PM, Avdi Grimm <av...@avdi.org> wrote:
>
>> Hi folks,
>>
>> I wrote a blog post with the intentionally provocative title above,
>> which can be found here:
>>

>> http://avdi.org/devblog/?p=18
>>
>
> I don't agree with the title, but I agree almost everything you said.

I'm strongly feel that James Britt has the right idea about this one.
We should view it as just another tool to be used where it works best
and I feel there are such places.

Assigning blame to a particular element of a programming language
seems foolish to me. I'm pretty confident I can write some code that
abuses the heck out of while loops. Should we start hating those now
too?

> * adding #to_* methods to String.

FasterCSV adds a to_csv() method to Array. What's that likely to
conflict with exactly? Other CSV libraries is the only thing I can
think of. I can live with that.

> I usually only do monkey patching in the
> following cases which have no reuse: top-level script, testing, and
> quick hacking.

I think it's the ideal tool for adding compatibility methods. Say you
want to write some code that works in Ruby 1.8 and 1.9, for example.
You can add the methods you need from 1.9 to 1.8 classes, with checks
to ensure they are only added if they don't exist already. I can't
think of a better solution than that.

James Edward Gray II


Eric Mahurin

unread,
Feb 24, 2008, 11:57:18 PM2/24/08
to
[Note: parts of this message were removed to make it a legal post.]

On Sun, Feb 24, 2008 at 10:02 PM, James Gray <ja...@grayproductions.net>
wrote:

> On Feb 23, 2008, at 4:23 PM, Eric Mahurin wrote:
>
> > On Sat, Feb 23, 2008 at 3:07 PM, Avdi Grimm <av...@avdi.org> wrote:
> >
> >> Hi folks,
> >>
> >> I wrote a blog post with the intentionally provocative title above,
> >> which can be found here:
> >>
> >> http://avdi.org/devblog/?p=18
> >>
> >
> > I don't agree with the title, but I agree almost everything you said.
>
> I'm strongly feel that James Britt has the right idea about this one.
> We should view it as just another tool to be used where it works best
> and I feel there are such places.
>
> Assigning blame to a particular element of a programming language
> seems foolish to me. I'm pretty confident I can write some code that
> abuses the heck out of while loops. Should we start hating those now
> too?


I don't think all language features are created equal. Some are more
dangerous than others. I think global variables are universally agreed to
be dangerous (in all languages), but most languages still support them
because they still can be useful. I believe monkey patching falls into the
same category. I think the point of this blog was to discourage people from
using it because it is dangerous. There are simple alternatives.

> * adding #to_* methods to String.
>
> FasterCSV adds a to_csv() method to Array. What's that likely to
> conflict with exactly? Other CSV libraries is the only thing I can
> think of. I can live with that.


I don't see the big advantage of Array#to_csv over a more traditional
CSV::from_a(arr), other than a few more characters to type. It is much more
encapsulated. The disadvantage of making Array#to_csv is that you are
modifying a global "variable" (the Array class).

> I usually only do monkey patching in the
> > following cases which have no reuse: top-level script, testing, and
> > quick hacking.
>
> I think it's the ideal tool for adding compatibility methods. Say you
> want to write some code that works in Ruby 1.8 and 1.9, for example.
> You can add the methods you need from 1.9 to 1.8 classes, with checks
> to ensure they are only added if they don't exist already. I can't
> think of a better solution than that.
>

Agreed. I also think this is an appropriate application of monkey
patching. I've done this myself too (maybe in a quiz). But, if this is in
a large system, you wouldn't want each package to do the same patching. It
would be best to separate the monkey patching and apply it at the top-level.

Eric

Jeremy McAnally

unread,
Feb 25, 2008, 12:29:24 AM2/25/08
to
>
> I don't think all language features are created equal. Some are more
> dangerous than others. I think global variables are universally agreed to
> be dangerous (in all languages), but most languages still support them
> because they still can be useful. I believe monkey patching falls into the
> same category. I think the point of this blog was to discourage people from
> using it because it is dangerous. There are simple alternatives.
>

Any language feature can be dangerous. "OMG YOU CAN OVERWRITE FILES
USING File.open()?? ITZ DESTROYING US!" As James said, you just have
to know when, why, and how to use it properly. The idiom is a very
powerful one if you use it with extreme caution. :)

>
> I don't see the big advantage of Array#to_csv over a more traditional
> CSV::from_a(arr), other than a few more characters to type.

It's not natural? You're probably returning a string but it looks
like you're asking for a CSV? To make matters worse, performance (in
my limited, completely contrived irb experiments) is slightly worse
with the from_a method.

> It is much more
> encapsulated. The disadvantage of making Array#to_csv is that you are
> modifying a global "variable" (the Array class).
>

That word doesn't mean what you think it means, I think. That isn't
"more encapsulated".

Even further, you're "modifying 'global variables'" any way you go.
If you add a method to CSV, you're still adding a method somewhere,
except now the API is awkward. So long as you document where the
method is added (whether it's Array or your own CSV class), you're not
hurting anyone. If people using your code hurt themselves because
they don't read documentation, that's their fault. The only
"dangerous" thing I see is perhaps namespace clashes, but in that
case, it's the developer's responsibility to keep track of those.
Even if you use your "encapsulated" version you could still have
another CSV module/class from a from_a method that stomps on that one.

It's a problem anywhere and not using monkeypatching just because
you're afraid of that issue seems a little silly to me. Then again,
maybe my systems (thankfully) haven't been "big" enough to really make
this a concern.

--Jeremy

--
http://jeremymcanally.com/
http://entp.com

Read my books:
Ruby in Practice (http://manning.com/mcanally/)
My free Ruby e-book (http://humblelittlerubybook.com/)

Or, my blogs:
http://mrneighborly.com
http://rubyinpractice.com

Marc Heiler

unread,
Feb 25, 2008, 12:33:23 AM2/25/08
to
> I think the point of this blog was to discourage people
> from using it because it is dangerous. There are simple alternatives.

Why is it dangerous?

Clifford Heath

unread,
Feb 25, 2008, 12:46:01 AM2/25/08
to
Phlip wrote:
> If so, and if it "can't be done in Ruby", why are there Ruby gems that talk
> about AOP?

Because what's called AOP isn't. There's always a better way
than the injection of code which is referred to as AOP, IMO.
I could argue this at length, but I hope that not many people
here actually care :-).

>> A more restricted version of this behaviour can be done by treating every
>> aspect-limited extension (which I call a facet) of an object, as a special
>> kind of subclass.
> That's probably the Ruby AOP packages. Thanks for the pointers!

If you want to stay in Ruby, you should use traits instead. It's a
little weaker than what I'd call "proper" AOP, but gets as close as
you can meaningfully get.


Clifford Heath.

Eivind Eklund

unread,
Feb 25, 2008, 6:27:09 AM2/25/08
to
On Sun, Feb 24, 2008 at 2:34 AM, Morton Goldberg
<m_gol...@ameritech.net> wrote:
> On Feb 23, 2008, at 6:56 PM, M. Edward (Ed) Borasky wrote:
> > One of my friends once passed this little quotation on to me:
> >
> > "Always code as if the person who will maintain your code is a
> > violent psychopath who knows where you live."
>
> Truly wonderful. If there were a poster of that available, I'd buy it
> and hang it where I could see it when I look up from my screen.
>
> You didn't make an attribution, so I presume you don't know who
> originated it. Too bad.

It is usually attributed to Martin Golding.

Eivind

Avdi Grimm

unread,
Feb 25, 2008, 8:24:24 AM2/25/08
to
On Sun, Feb 24, 2008 at 11:02 PM, James Gray <ja...@grayproductions.net> wrote:
> Assigning blame to a particular element of a programming language
> seems foolish to me. I'm pretty confident I can write some code that
> abuses the heck out of while loops. Should we start hating those now
> too?

If you read the post, you'll see that I'm not blaming monkey-patching
- I'm blaming the faddish overuse of it when simpler methods would
suffice. Like I said in the post, it's a cultural issue, not a
technical one.

--
Avdi

Avdi Grimm

unread,
Feb 25, 2008, 8:30:51 AM2/25/08
to
On Mon, Feb 25, 2008 at 12:33 AM, Marc Heiler <shev...@linuxmail.org> wrote:
> Why is it dangerous?

One of the reasons concepts like modules and classes were introduced
to programming languages was to reduce accidental collisions. Monkey
patching discards all of that. In a sufficiently large project where
monkey patching isn't vigorously discouraged, unexpected and extremely
difficult to debug interactions are almost inevitable, because monkey
patches by different authors (or by the same author at different
times) interact or collide in unpredictable ways.

Where this becomes a community problem and not just a team problem is
when authors of gems and plugins start to see monkey patching as "the"
way to write extensions in Ruby. Thus making such unpredictable
interactions practically unavoidable if you want to re-use anyone
else's code.

--
Avdi

James Gray

unread,
Feb 25, 2008, 8:59:12 AM2/25/08
to
On Feb 25, 2008, at 7:24 AM, Avdi Grimm wrote:

> On Sun, Feb 24, 2008 at 11:02 PM, James Gray <ja...@grayproductions.net
> > wrote:
>> Assigning blame to a particular element of a programming language
>> seems foolish to me. I'm pretty confident I can write some code that
>> abuses the heck out of while loops. Should we start hating those now
>> too?
>
> If you read the post, you'll see that I'm not blaming monkey-patching
> - I'm blaming the faddish overuse of it when simpler methods would
> suffice.

Thanks for the concern, but I did read your article.

> Like I said in the post, it's a cultural issue, not a technical one.

I'm just uncomfortable judging an entire community with sweeping
stereotypes. I have no idea what you are coding, for example, and
thus I don't feel I can speak intelligently about what you should or
should not be using.

James Edward Gray II

Eric Mahurin

unread,
Feb 25, 2008, 10:07:51 AM2/25/08
to
[Note: parts of this message were removed to make it a legal post.]

On Sun, Feb 24, 2008 at 11:33 PM, Marc Heiler <shev...@linuxmail.org>
wrote:

> > I think the point of this blog was to discourage people
> > from using it because it is dangerous. There are simple alternatives.
>
> Why is it dangerous?


It is equivalent to modifying global variables. Modifying globally
accessible classes (not just meta-classes) should be exception, not the
rule.

matz also agrees that monkey patching is dangerous. Here are a few quotes:

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/172172

"open class" is so strong (often too strong), we can break things easily. In
other word, Ruby trust you to give you sharp knives, where Python don't.
From the Python point of view, it's wrong, I guess.

http://www.rubyist.net/~matz/slides/rc2005/mgp00031.html

- Open class is Too Dangerous
- Global Modification

Until there is a "safe" way (i.e. namespaces) for monkey patching (opening
global classes), I think it should be discouraged. Discouraged, not
banned. It still is a tool that can be used, but it shouldn't be the first.

aema...@gmail.com

unread,
Feb 25, 2008, 11:43:31 AM2/25/08
to
On Feb 23, 5:26 pm, Avdi Grimm <a...@avdi.org> wrote:
> On Sat, Feb 23, 2008 at 7:13 PM, Marc Heiler <sheve...@linuxmail.org> wrote:
> > It is frustrating to try to read a blog that claims monkey patching is
> > destroying ruby when in actuality the author meant Rails.
>
> No, I meant ruby. I have been coding in Ruby for ~7 years, since long
> before Rails appeared. At work I'm the first to correct people when
> they make a comment about "Ruby" when they really are talking about a
> Rails-specific feature.
>
> Yes, I used a Rails example. And I suspect that it's true that the
> phenomenon is more prevalent in in the Rails community than in the
> wider Ruby community. But for better or worse the majority of Ruby
> code being written today is being written for Rails, and the Ruby
> coders of tomorrow are cutting their teeth in the Rails community.
> Rails cultural problems will, increasingly, be Ruby cultural
> problems.
>
> --
> Avdi

Sorry but you are contradicting yourself. Part of growing in the Ruby
culture is learning the difference between both communities and how
they overlap. I got into Ruby because of Rails and I can tell the
difference very easily. Did it take me some time? Yes. Was it worth
it? Definitely. So, please, don't make it harder for the people that
are new to understand the difference between the communities by
muddling the waters.

AEM

Michal Suchanek

unread,
Feb 25, 2008, 5:53:02 PM2/25/08
to
On 24/02/2008, M. Edward (Ed) Borasky <zn...@cesmail.net> wrote:

> Avdi Grimm wrote:
> > Hi folks,
> >
> > I wrote a blog post with the intentionally provocative title above,
> > which can be found here:
> >
> > http://avdi.org/devblog/?p=18
> >
>
> > While the title is a bit of deliberate hyperbole, I am genuinely
> > troubled about the popularization of monkey patching in the Ruby
> > community. I explain my reasons more thoroughly in the post, but
> > here's a synopsis:
> >
> > Monkeypatching has become the hip thing to do in the
> > Ruby and (especially?) Rails communities, and it has
> > reached the point where experienced programmers are
> > turning to it as the tool of first resort *even* when there
> > is a simpler, more traditional solution available. I
> > suggest that it's time for Ruby hackers to start setting a
> > better example.
>
> >
> > My hope with this post is to start a conversation about fostering
> > robust software extension mechanisms in the Ruby ecosystem. I welcome
> > any comments, both here and on the blog.
> >
>
>
> One of my friends once passed this little quotation on to me:
>
> "Always code as if the person who will maintain your code is a violent
> psychopath who knows where you live."

You know, you can interpret this both ways. Either write your code so
trouble-free that he never notices it or make it such that he gets a
heart attack the moment he tries to to look at it/use it.

Of course depending on the thing you write one approach may be more
likely to succeed than the other ..

Thanks

Michal

M. Edward (Ed) Borasky

unread,
Feb 25, 2008, 11:11:15 PM2/25/08
to

I actually first heard it from Martin Golding, and I've forgotten how
long ago that was. I did a Google search the other day and quite a few
hits came up for Damien Conway.

Pit Capitain

unread,
Feb 26, 2008, 3:31:31 AM2/26/08
to
2008/2/25, Clifford Heath <n...@spam.please.net>:

> Phlip wrote:
> > I want .inspect, or whatever, outside my module, to behave normally. But if
> > you inspect a string while my module is above you on the call stack, I get
> > my hotwired version of .inspect.
> > Does anyone have a Ruby Hack which does that yet? How hard would it be?
>
> It can't be done in Ruby. (...)

I would be *very* careful with sentences like this. Remember, this is
Ruby. This topic has been discussed more than once on the mailing
list. For example look at ruby-talk:244014. Here's the example Phlip
talks about:

require "import-module-extended"

module MyModule
extending(String) do
def inspect
return 'shock the monkey'
end
end
def call_show(str)
show(str)
end
end

class MyClassA
def call_show(str)
show(str)
end
def show(str)
p str
end
end

class MyClassB
include MyModule
def show(str)
p str
end
end

MyClassA.new.call_show("hi") # => "hi"
MyClassB.new.call_show("hi") # => shock the monkey

Regards,
Pit

PS: I can't find Phlip's posts in the ruby-talk archives...

Bill Kelly

unread,
Feb 26, 2008, 5:54:29 AM2/26/08
to

From: "Pit Capitain" <pit.ca...@gmail.com>

>
> PS: I can't find Phlip's posts in the ruby-talk archives...

I don't know if this will turn out to be related or not, but
something similar happened to me. My posts are missing from
the ruby-talk archives for a period of over a year (October
2006 - November 2007.) They do show up in a Google groups
search. (I post directly to the mailing list though, not to
the newsgroup.)


Regards,

Bill

Clifford Heath

unread,
Feb 26, 2008, 6:50:37 AM2/26/08
to
Pit Capitain wrote:
> 2008/2/25, Clifford Heath <n...@spam.please.net>:
>> Phlip wrote:
>> > I want .inspect, or whatever, outside my module, to behave normally. But if
>> > you inspect a string while my module is above you on the call stack, I get
>> > my hotwired version of .inspect.
>> > Does anyone have a Ruby Hack which does that yet? How hard would it be?
>>
>> It can't be done in Ruby. (...)
>
> I would be *very* careful with sentences like this.

You can do the special case that Phlip described. You can't do the
general thing which he was exemplifying without doing stupid things
like inspecting caller. I've also done quite a bit of deep metaprogramming
in Ruby, and what he wants (as opposed to his simple example) can't
sensibly be done, and probably shouldn't be anyway. Caller sensitivity
violates POLS.

John Wilger

unread,
Feb 26, 2008, 10:05:54 AM2/26/08
to
On Feb 24, 8:57 pm, Eric Mahurin <eric.mahu...@gmail.com> wrote:
> I don't see the big advantage of Array#to_csv over a more traditional
> CSV::from_a(arr), other than a few more characters to type.  It is much more
> encapsulated.

The big advantage is that, when writing a method that needs to receive
CSV data as an argument, you don't have to do type checking on the
argument - any object that responds correctly to the #to_csv message
can be used.

def i_need_csv( obj )
data = obj.to_csv
do_something_with( data )
end

This gives more freedom to the user of the library who might have an
object of their own class which knows how to turn itself into CSV
data. Your suggestion would lead to something like:

def i_need_csv( obj )
data = case obj
when Array
CSV::from_a( obj )
when Hash
CSV::from_hash( obj )
else
raise "Sorry, I'm not duck-type friendly!"
end
end

Yuck.

> The disadvantage of making Array#to_csv is that you are
> modifying a global "variable" (the Array class).

I'll take that disadvantage (in combination with good test coverage!)
over having to write verbose, type-checking code any day.

--
Regards,

John Wilger

Pit Capitain

unread,
Feb 26, 2008, 10:07:43 AM2/26/08
to
2008/2/26, Clifford Heath <n...@spam.please.net>:

> You can do the special case that Phlip described. You can't do the
> general thing which he was exemplifying without doing stupid things
> like inspecting caller. I've also done quite a bit of deep metaprogramming
> in Ruby, and what he wants (as opposed to his simple example) can't
> sensibly be done, and probably shouldn't be anyway. Caller sensitivity
> violates POLS.

Could you describe "the general thing" a little bit more? As I
understood it, he wants to limit a "monkey patch" to the scope of a
Module. Which is what I've done. I've only used the import-module
library and added a more user-friendly syntax. I'm not inspecting
caller at all, and import-module doesn't either. What am I missing?

Jones, Brian - McClatchy Interactive

unread,
Feb 26, 2008, 10:45:27 AM2/26/08
to
I'd be at least a little interested in potentially offering developers
the chance to 'lock' their classes from monkey patches. This could be
useful to the 'core' library that comes with Ruby, and to at least make
developers look at extension points provided via an actual API instead
of just immediately jumping on monkey patching for solving all problems.

Brian

James Gray

unread,
Feb 26, 2008, 10:52:36 AM2/26/08
to
On Feb 26, 2008, at 9:45 AM, Jones, Brian - McClatchy Interactive wrote:

> I'd be at least a little interested in potentially offering developers
> the chance to 'lock' their classes from monkey patches.

There are probably ways around this, but:

>> Array.freeze
=> Array
>> class Array
>> def to_csv; end
>> end
TypeError: can't modify frozen class
from (irb):7

James Edward Gray II


Jari Williamsson

unread,
Feb 26, 2008, 11:07:35 AM2/26/08
to
John Wilger wrote:
>> The disadvantage of making Array#to_csv is that you are
>> modifying a global "variable" (the Array class).
>
> I'll take that disadvantage (in combination with good test coverage!)
> over having to write verbose, type-checking code any day.

IMO, this is not an either/or case. Why not just add to_csv() only to
the instance who actually could need it?

To me, a big part of the duck typing concept is to define an object for
what it really describes, not just lazily include every method you might
or might not need.


Best regards,

Jari Williamsson

ThoML

unread,
Feb 26, 2008, 11:34:37 AM2/26/08
to
> I'd be at least a little interested in potentially offering developers
> the chance to 'lock' their classes from monkey patches.

IMHO part of the problem rather is that ruby by its own actually
doesn't provide a way to do this systematically. IIRC there was some
talk about stacked methods in ruby 1.9.x but I personally would rather
vote (if there were a vote) for something simpler like advices as they
are used, e.g., in emacs lisp. No matter what one thinks of elisp,
Emacs is a rather complex system and advices are used in several parts
of the system and IMHO they have proven as a simple yet versatile and
rather robust way to achieve what often is summarized as MP. I suppose
a standardized defadvice would be more robust than the current eval-
or alias-based hacks. And since Emacs is a complex system that makes
heavy use of these techniques, one could probably learn from it.

I know this can be done in pure ruby as it is today rather easily. My
point rather is this should somehow be standardized, i.e. the standard
library should provide standard means to do this.

Regards,
Thomas.

Trans

unread,
Feb 26, 2008, 12:12:42 PM2/26/08
to

On Feb 26, 10:45 am, "Jones, Brian - McClatchy Interactive"

That's ridiculous.

Look. What is the problem? That I might extend a class and you might
extend a class with the same method and thus we can't use each others
code in the same program? Forget overriding core/standard methods --
anyone who does that knows they must do so with SUPER EXTREME caution.
But if someone is writing and end-user application, it doesn't really
matter one way of the other --the code is not intended to be shared.
Extend to your hearts desire. One only needs to be aware of potential
conflicts with 3rd party libs they might use. And for those, in which
the developer is intending for their code to be reusable, then the
developer needs to tread more carefully and follow some simple rules.
Only extend core and standard classes when it's a very clear and
general need. In which case it's a good idea to checkout projects that
attempt to provide some general standardization around such methods
(eg. Facets). It's likely your method is already available, and your
lib's users can have a reasonable basis for knowing what to expect.
Beyond that, if you still really want to extend a core/standard class
in a way vunique to your particular program then give it an equally
unique name --generally putting you project's name as the first part
of the method. For example, the YAML lib adds methods like
#yaml_properties.

By following these rules, getting along with other programs is a
pretty safe bet. And we don't need to add restrictions that will just
make life harder when we do have good reasons to MP.

I should point out one other rule of thumb often overlooked as a
consequence of MP: DO NOT use #respond_to? as a means of determining
if an object is extended by a module or is an instance of some class/
superclass. That's much more likely to lead to unexpected issues with
MPs.

T.

Joel VanderWerf

unread,
Feb 26, 2008, 1:17:36 PM2/26/08
to
Jari Williamsson wrote:
> John Wilger wrote:
>>> The disadvantage of making Array#to_csv is that you are
>>> modifying a global "variable" (the Array class).
>>
>> I'll take that disadvantage (in combination with good test coverage!)
>> over having to write verbose, type-checking code any day.
>
> IMO, this is not an either/or case. Why not just add to_csv() only to
> the instance who actually could need it?

How far in advance do you know that an instance needs this method?

If you wait too long, you end up with another case statement (again, on
the class of the object, yuck) to decide which #to_csv is appropriate
for the object.

If you add #to_csv eagerly, then the requirement that this object
respond to #to_csv becomes a strong coupling between the point of
creation and the #i_need_csv implementation.

--
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

James Britt

unread,
Feb 26, 2008, 1:25:23 PM2/26/08
to
Trans wrote:
>
> On Feb 26, 10:45 am, "Jones, Brian - McClatchy Interactive"
> <bjo...@mcclatchyinteractive.com> wrote:
>> I'd be at least a little interested in potentially offering developers
>> the chance to 'lock' their classes from monkey patches. This could be
>> useful to the 'core' library that comes with Ruby, and to at least make
>> developers look at extension points provided via an actual API instead
>> of just immediately jumping on monkey patching for solving all problems.
>
> That's ridiculous.

Fears about open classes sound very much like what people say about
dynamic typing.

"#{@core_feature} is unpredictable!"

"#{@core_feature} creates problems that cannot be found until run-time!"

"#{@core_feature} is unsafe!"

"#{@core_feature} should be locked down!"

It's not that these claims are entirely untrue, it's just that, in real
life, most people simply do not encounter the alleged problems.

Code that is poorly written or does not play well with others tends to
get discarded.

--
James Britt

"Trying to port the desktop metaphor to the Web is like working
on how to fuel your car with hay because that is what horses eat."
- Dare Obasanjo

Eric Mahurin

unread,
Feb 26, 2008, 1:32:22 PM2/26/08
to
[Note: parts of this message were removed to make it a legal post.]


Point taken. Monkey patching might be the best solution in this situation.
Assuming you want to be able to convert any arbitrary object to a CSV, this
might be best.

Another possibility would be something like this:

module CSV
From = {
Array => proc {|a| ...}
Hash => proc {|h| ...}
...
}
...

Then use CSV::From[obj]. The problem is that if you build a class later
that wants to work with CSV, you'd need to modify this CSV::From "global".
This "global" modification isn't much better than monkey patching "global"
modification.

I think John does illustrate why monkey patching can be useful with
duck-typing. In statically-typed languages (like C++), the above can be
solved by overloading a global function based on type (type should prevent
collisions). Don't take this to mean I want static-typing. I'm the biggest
fan duck-typing.

Still, we should not use monkey patching as our first tool. We should think
of it just like global variable modification, IMO.

Eric

Avdi Grimm

unread,
Feb 26, 2008, 1:43:23 PM2/26/08
to
On Tue, Feb 26, 2008 at 1:25 PM, James Britt <james...@gmail.com> wrote:
> It's not that these claims are entirely untrue, it's just that, in real
> life, most people simply do not encounter the alleged problems.
>
> Code that is poorly written or does not play well with others tends to
> get discarded.

Except that I'm working in the real world, and I run into these
problems practically every day. Read through some Rails plugin code
sometime - nearly every significant, popular Rails plugin does what it
does by re-opening classes. Probably because this is the coding style
that Rails demonstrates and encourages. Now we can argue about this
being a Rails problem rather than a Ruby one, but again, that's where
people are learning the language these days.

If you have the luxury of working on small projects with few
developers and the time to develop everything in-house rather than
relying on third-party gems and plugins, that's great. But I and the
people I know *are* encountering these problems. And in the majority
of cases, they are *completely* *avoidable*. And there is usually
nothing about the problem that makes a monkey-patch a desirable or
even an easier way to implement the feature - it's simply done that
way because that's how everyone else is doing it.

--
Avdi

Jari Williamsson

unread,
Feb 26, 2008, 1:43:53 PM2/26/08
to

I don't think it would matter in this case. You should be able to create
a dynamic implementation without case statements, since a CSV
implementation would be dependent on the #to_a method? (And #to_a for an
array object just returns self.)


Best regards,

Jari Williamsson

MenTaLguY

unread,
Feb 26, 2008, 2:10:57 PM2/26/08
to
On Wed, 27 Feb 2008 00:45:27 +0900, "Jones, Brian - McClatchy Interactive" <bjo...@mcclatchyinteractive.com> wrote:
> I'd be at least a little interested in potentially offering developers
> the chance to 'lock' their classes from monkey patches.

You can do this today if you want; all you need to do is freeze the class.

class Foo
# ... your definitions
end

Foo.freeze # Foo is no longer an open class

-mental


Clifford Heath

unread,
Feb 26, 2008, 5:25:17 PM2/26/08
to
Pit Capitain wrote:
> Could you describe "the general thing" a little bit more? As I
> understood it, he wants to limit a "monkey patch" to the scope of a
> Module. Which is what I've done. I've only used the import-module
> library and added a more user-friendly syntax. I'm not inspecting
> caller at all, and import-module doesn't either. What am I missing?

Well, I can't find import-module-extended, but assuming it's like
import-module... you're missing:

* performance
* isolation of instance variables that the extensions might create
* ability for an extended class to *always* appear extended when
called from anywhere in a class that knows about those extensions,
without having to constantly remember to add the extensions on each
call.

Is that enough to claim "no sensible way" of doing it?

furtiv...@gmail.com

unread,
Feb 26, 2008, 9:41:25 PM2/26/08
to
On Feb 26, 11:34 am, ThoML <micat...@gmail.com> wrote:
> [...]

> My point rather is this should somehow be standardized, i.e. the standard
> library should provide standard means to do this.
>

This is what I was attempting to say in my previous post on this
thread. You mentioned defadvice, which is a good example of a "long
reach" mechanism employed by top-level code in order to tweak lower-
level code. The reason this thread exists is because there is no
centralized mechanism in ruby to help programmers from stepping on
each others' toes. Making ad hoc modifications to base-level classes
is not a scalable practice.

So I will ask my question again: Is (or was) there a serious plan for
something like selector namespaces in ruby 2.0? I found
http://rubygarden.org/ruby/page/show/Rite
which appears to be down; google cache:
http://64.233.169.104/search?q=cache:ej4aPcNY41QJ:rubygarden.org/ruby/page/show/Rite+http://rubygarden.org/ruby/page/show/Rite&hl=en&ct=clnk&cd=1&gl=us

Responses such as "What is the problem?" come from those who have been
lucky enough to evade these issues in their own work. But eventually
one will wish to use some code written by someone else which
introduces conflicts. It's only a matter of time, unless you
personally write every line of code in your project. So the answer to
"What is the problem?" is that the technique doesn't scale.

--FC

Robert Dober

unread,
Feb 27, 2008, 12:57:15 AM2/27/08
to
On Tue, Feb 26, 2008 at 4:52 PM, James Gray <ja...@grayproductions.net> wrote:
> On Feb 26, 2008, at 9:45 AM, Jones, Brian - McClatchy Interactive wrote:
>
> > I'd be at least a little interested in potentially offering developers
> > the chance to 'lock' their classes from monkey patches.
>
> There are probably ways around this, but:
Hmm I do not think that one can overrule freeze; I never found a way,
anyone else?
Cheers
Robert
--
http://ruby-smalltalk.blogspot.com/

---
Whereof one cannot speak, thereof one must be silent.
Ludwig Wittgenstein

Joel VanderWerf

unread,
Feb 27, 2008, 1:12:42 AM2/27/08
to
Robert Dober wrote:
> On Tue, Feb 26, 2008 at 4:52 PM, James Gray <ja...@grayproductions.net> wrote:
>> On Feb 26, 2008, at 9:45 AM, Jones, Brian - McClatchy Interactive wrote:
>>
>> > I'd be at least a little interested in potentially offering developers
>> > the chance to 'lock' their classes from monkey patches.
>>
>> There are probably ways around this, but:
> Hmm I do not think that one can overrule freeze; I never found a way,
> anyone else?
> Cheers
> Robert

You can monkeypatch Class#freeze, as long as you get there first ;)

class Class
def freeze; end
end

class Foo
def bar; end
end

Foo.freeze

class Foo
def zap; end
end

Trans

unread,
Feb 27, 2008, 6:36:35 AM2/27/08
to

On Feb 26, 9:44 pm, furtive.cl...@gmail.com wrote:
> On Feb 26, 11:34 am, ThoML <micat...@gmail.com> wrote:
>
> > [...]
> > My point rather is this should somehow be standardized, i.e. the standard
> > library should provide standard means to do this.
>
> This is what I was attempting to say in my previous post on this
> thread. You mentioned defadvice, which is a good example of a "long
> reach" mechanism employed by top-level code in order to tweak lower-
> level code. The reason this thread exists is because there is no
> centralized mechanism in ruby to help programmers from stepping on
> each others' toes. Making ad hoc modifications to base-level classes
> is not a scalable practice.
>
> So I will ask my question again: Is (or was) there a serious plan for

> something like selector namespaces in ruby 2.0? I foundhttp://rubygarden.org/ruby/page/show/Rite
> which appears to be down; google cache:http://64.233.169.104/search?q=cache:ej4aPcNY41QJ:rubygarden.org/ruby...

Solutions to this tend to be pretty weighty. Ruby is already a rather
slow language. A while back I suggested this idea:

module MyModule
class String < ::String
def something; "something"; end
end

def self.tryme
"string".something
end
end

def tryme2
"string".something
end

MyModule.tryme #=> "sometging"
tryme2 #=> NoMethodError

Austin thought it was the worst idea in the world. He may be right,
I'm not sure. In either case it would add another level of
consideration to the language.

> Responses such as "What is the problem?" come from those who have been
> lucky enough to evade these issues in their own work. But eventually
> one will wish to use some code written by someone else which
> introduces conflicts. It's only a matter of time, unless you
> personally write every line of code in your project. So the answer to
> "What is the problem?" is that the technique doesn't scale.

What technique is perfectly scalable? There is always the potential of
name clash no matter what technique is used. It's an unfortunate fact
of life, but if the library you are trying to use is poorly written --
well, then life sucks. Fix the library or find another.

I think you may be looking foe a magic bullet that doesn't exist.
Also, do you have examples of this issue?

T.

Eivind Eklund

unread,
Feb 27, 2008, 8:30:20 AM2/27/08
to
On Tue, Feb 26, 2008 at 7:25 PM, James Britt <james...@gmail.com> wrote:
> Code that is poorly written or does not play well with others tends to
> get discarded.

We still have Gems, which don't play well at all with others (on a
technical basis) - witness the conflicts with the Debian team, and
what every other Unix package maintainer says about this. This proves
that this mechanism doesn't work so well if there is a size/momentum
advantage.

Also, discussing what is appropriate and not is a good way to educate
people, and to help us all learn to think more clearly in the area.

Eivind.

James Gray

unread,
Feb 27, 2008, 8:46:43 AM2/27/08
to
On Feb 24, 2008, at 10:02 PM, James Gray wrote:

> On Feb 23, 2008, at 4:23 PM, Eric Mahurin wrote:
>
>> I usually only do monkey patching in the
>> following cases which have no reuse: top-level script, testing, and
>> quick hacking.
>
> I think it's the ideal tool for adding compatibility methods.

Along these lines, I read a chapter in Design Patterns in Ruby last
night that suggests using Ruby's open classes as one possible way to
implement the Adapter pattern. The book includes a pretty good
discussion of the plusses and minus to this approach and makes
recommendations about when it's probably worth the trade-off. It's a
good read.

James Edward Gray II

Jones, Brian - McClatchy Interactive

unread,
Feb 27, 2008, 9:20:41 AM2/27/08
to
> On Tue, Feb 26, 2008 at 1:25 PM, James Britt
> <james...@gmail.com> wrote:
> > It's not that these claims are entirely untrue, it's just that, in
> > real life, most people simply do not encounter the
> alleged problems.
> >
> > Code that is poorly written or does not play well with
> others tends
> > to get discarded.
>
> Except that I'm working in the real world, and I run into
> these problems practically every day.

It may be enough to simply have ruby warn us when and where a class has
been re-opened and a means to ignore it by file/path or namespace if we
want.

Brian

Eric Mahurin

unread,
Feb 27, 2008, 9:38:35 AM2/27/08
to
[Note: parts of this message were removed to make it a legal post.]

On Wed, Feb 27, 2008 at 7:46 AM, James Gray <ja...@grayproductions.net>
wrote:


I don't have the book. I wouldn't mind seeing the +/- list.

You are talking about this, right?

http://en.wikipedia.org/wiki/Adapter_pattern

Using what this link above suggests (adapter "has-a" or "is-a" adaptee) is
the better way to go, IMO. There are multiple ways to do this in Ruby.
Monkey-patching/open-classes makes the solution: adapter IS adaptee. I
don't know if you can even call it the adapter pattern since you are
destroying the adaptee interface.

James Gray

unread,
Feb 27, 2008, 10:01:38 AM2/27/08
to
On Feb 27, 2008, at 8:38 AM, Eric Mahurin wrote:

> On Wed, Feb 27, 2008 at 7:46 AM, James Gray
> <ja...@grayproductions.net>
> wrote:
>
>> On Feb 24, 2008, at 10:02 PM, James Gray wrote:
>>
>>> On Feb 23, 2008, at 4:23 PM, Eric Mahurin wrote:
>>>
>>>> I usually only do monkey patching in the
>>>> following cases which have no reuse: top-level script, testing, and
>>>> quick hacking.
>>>
>>> I think it's the ideal tool for adding compatibility methods.
>>
>> Along these lines, I read a chapter in Design Patterns in Ruby last
>> night that suggests using Ruby's open classes as one possible way to
>> implement the Adapter pattern. The book includes a pretty good
>> discussion of the plusses and minus to this approach and makes
>> recommendations about when it's probably worth the trade-off. It's a
>> good read.
>>
>> James Edward Gray II
>
>
> I don't have the book. I wouldn't mind seeing the +/- list.

I don't think I would do it much justice condensing it down for this
email, but it basically amounted to how well you know the code you are
adapting and how simple the changes are. The author felt it was
probably OK if you knew the class involved well and you were just
aliasing a method or two. Again though, I'm grossly simplifying here.

The book also talked about adding the methods needed to the singleton
class of individual objects. I thought that was an awesome twist that
we probably don't consider enough.

> You are talking about this, right?
>
> http://en.wikipedia.org/wiki/Adapter_pattern

Yes.

> I don't know if you can even call it the adapter pattern since you are
> destroying the adaptee interface.

I view it as a Ruby way to think about the problem. Don't they always
say that intent is the most important aspect to the design patterns?

James Edward Gray II


Trans

unread,
Feb 27, 2008, 10:04:58 AM2/27/08
to

On Feb 27, 8:30 am, "Eivind Eklund" <eekl...@gmail.com> wrote:


> On Tue, Feb 26, 2008 at 7:25 PM, James Britt <james.br...@gmail.com> wrote:
> > Code that is poorly written or does not play well with others tends to
> > get discarded.
>
> We still have Gems, which don't play well at all with others (on a
> technical basis) - witness the conflicts with the Debian team, and
> what every other Unix package maintainer says about this. This proves
> that this mechanism doesn't work so well if there is a size/momentum
> advantage.

I would now suggest that it is the FHS that is holding us back, not
the other way around --talk about your size/momentum advantage.

Suggested reading:

http://gobolinux.org/index.php?page=doc/articles/clueless

> Also, discussing what is appropriate and not is a good way to educate
> people, and to help us all learn to think more clearly in the area.

Very true.

T.

Pit Capitain

unread,
Feb 27, 2008, 11:35:37 AM2/27/08
to
2008/2/26, Clifford Heath <n...@spam.please.net>:

> Well, I can't find import-module-extended, but assuming it's like
> import-module... you're missing:

Clifford, thanks for listing your requirements.

> * performance

Comparable to other AOP frameworks in Ruby. That might be an obstacle
for you, but it's not for me yet.

> * isolation of instance variables that the extensions might create

If you are really serious about this, there are ways to achieve this goal.

> * ability for an extended class to *always* appear extended when
> called from anywhere in a class that knows about those extensions,
> without having to constantly remember to add the extensions on each
> call.

Please look at my sample code again. It does exactly what you describe.

> Is that enough to claim "no sensible way" of doing it?

Not for me, as I said above. But since there's no formal definition of
"sensible ways", there might be no sensible way for you. Maybe we
should take this to another thread or to private mail if you want to
discuss it further.

Regards,
Pit

Rick DeNatale

unread,
Feb 27, 2008, 12:42:10 PM2/27/08
to

In the case of Debian and Gems, I think it's a mixture of a somewhat
draconian interpretation of the FHS, and a desire to make the gems
themselves somehow work like debian packages, which don't envision
things like having multiple versions of a gem installed concurrently.

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

s.ross

unread,
Feb 27, 2008, 1:44:04 PM2/27/08
to
On Feb 27, 2008, at 6:20 AM, Jones, Brian - McClatchy Interactive wrote:

>> It may be enough to simply have ruby warn us when and where a class
>> has
> been re-opened and a means to ignore it by file/path or namespace if
> we
> want.

This whole thing is a complex philosophical discussion about the goals
of the language and the problems that could be encountered if...

Perhaps someone could, instead of debating the theory, the impacts on
scaling, and the philosophy, come up with a patch and run it by Ruby
core for comment. Otherwise this thread could continue forever with
those who find monkey patching useful saying ... um ... "I find monkey
patching useful" and those who have issues with open classes
saying ... um ... "it's not scalable, it's surprising, it's destroying
Ruby, etc."

The arguments are out there. What it takes is a stake in the ground (a
patch) that demonstrates some "better way" that doesn't cause Ruby to
break existing applications.

FWIW, I'm in the first camp, and feel Ruby does just fine for my
needs. I understand the arguments to the contrary, but don't
anticipate them being a problem in my application space. That's not to
claim validity of either position, just disclosure of my predisposition.

Cheers,

Steve

Avdi Grimm

unread,
Feb 27, 2008, 1:52:11 PM2/27/08
to
On Wed, Feb 27, 2008 at 1:44 PM, s.ross <cwd...@gmail.com> wrote:
> FWIW, I'm in the first camp, and feel Ruby does just fine for my
> needs. I understand the arguments to the contrary, but don't
> anticipate them being a problem in my application space. That's not to
> claim validity of either position, just disclosure of my predisposition.

If that's how you personally divide things, then I'm in your camp too.
No, really.

I'm actually not very interested in any of the proposals to extend
Ruby (either with patches or with Ruby code). I'll be completely
satisfied if, as a result of this discussion, a few more people think
"oh yeah, I could do this with [inheritance|mixins|delegation|etc.],
and it would be easier than monkey patching!" when they set out to add
some functionality to an existing class.

As far as the language goes, I'm happy with Ruby the way it is.

--
Avdi

Robert Dober

unread,
Feb 27, 2008, 6:27:55 PM2/27/08
to

That indeed is a truly perverse use case for MP, you have my deepest respect ;).
It is indeed an extreme example what the enabling approach can lead
to, but it is maybe not a coincidence that it was Smalltalk which
really brought up UT first IIRC?
That is something we should add into this discussion, MP might be a
danger for Ruby to be extincted (I do not believe so but just for the
sake of argument), TDD (or BDD) might save it somehow.
But there is no doubt it is not much of a relief if somebody released
something stupid in a library and now a zillion tests do not pass
anymore.

Just out of curiosity why does Class#freeze need to exist and cannot
be inherited from Object#freeze?

Joel VanderWerf

unread,
Feb 28, 2008, 12:51:34 AM2/28/08
to
Robert Dober wrote:
> Just out of curiosity why does Class#freeze need to exist and cannot
> be inherited from Object#freeze?

Because Module#freeze is defined by ruby (so redefining Object#freeze
would not have the desired effect in this case).

Eivind Eklund

unread,
Feb 28, 2008, 3:06:55 AM2/28/08
to
On Wed, Feb 27, 2008 at 4:04 PM, Trans <tran...@gmail.com> wrote:
> On Feb 27, 8:30 am, "Eivind Eklund" <eekl...@gmail.com> wrote:
>
> > On Tue, Feb 26, 2008 at 7:25 PM, James Britt <james.br...@gmail.com> wrote:
> > > Code that is poorly written or does not play well with others tends to
> > > get discarded.
> >
> > We still have Gems, which don't play well at all with others (on a
> > technical basis) - witness the conflicts with the Debian team, and
> > what every other Unix package maintainer says about this. This proves
> > that this mechanism doesn't work so well if there is a size/momentum
> > advantage.
>
> I would now suggest that it is the FHS that is holding us back, not
> the other way around --talk about your size/momentum advantage.
>
> Suggested reading:
>
> http://gobolinux.org/index.php?page=doc/articles/clueless

I perfectly agree that a large part of the reason the FHS is the way
it is (and why we're using FHS or something similar on most Unix
systems) is historical momentum. I feel that's a tangent, though.

In my opinion, the core issue is that people should be able to expect
a single directory layout on a single operating system, so the
operating system owns the directory layout. If you are going to write
a package manager that works on different operating systems, it should
be able to adopt to the conventions of those operating systems, or it
hose the users of the operating systems. Users that don't care if a
package is written in Ruby, or in Python, or in C, or whatever.

I think having different operating systems - like GoboLinux, like Mac
OS X, like Windows - that experiment with different layouts is a good
thing. There may well be other layouts that work better than the
traditional one these days. I just think this is an area for
operating systems to experiment, not programming languages.

Eivind.

Florian Gilcher

unread,
Feb 28, 2008, 9:16:24 AM2/28/08
to
Hi,

I have read all other Statements in this thread, but as it is such a
vast collection of opinions, its hard to keep track. So: if I mention
something for the second time, please ignore it ;).

I think the problem with MonkeyPatching is clear: it is a hack and
hacks tend to die soon. I am strongly opposed to use it in an official
release without thinking twice. Usually, there is a better way to
solve the problem. When browsing Rails plugins (i don't want to bash
rails, but thats an incredibly big source third-party-libraries), I
often see gruesome hacks to solve problems that could easily be solved
otherwise - because the author obviously didn't know about the right
way. Some time ago, many plugins had some implementation of
String#constantize (better, worse, the same as the Rails version).
This shows one thing:
Plugin authors are not aware of everything the language has to offer.
So they do what they do best. Which is not always good. The other side
of the problem is that the target of your patch is not written to be
extended (have a look at the "render"-Method in rails) - so you only
quick resort is a hack.
Monkeypatching is cool - if you think well an at least twice about it.

The problems with meta-programming is another one:
We love it. We advertise it as core features of the language (which -
in my book - it is not).

Take the above example: Array#to_csv

Why not CSV.from(arg)? It is cumbersome to read and we need to think
about a way to split the implementation details of from(Array) and
from(otherType) in halves. But from an OO-perspective, it makes
perfect sense: an Array doesn't have to care about the types that it
can be converted into an it is well encapsulated.

But, because we are lazy, lazy ruby programmers, we love our
object.send syntax. So we implement a shorthand method. Another
example is Object.in?(), often seen as a shorthand for
some_collection.contains?(obj) (Im not sure, but this is called
'grief', afaik). The first is nicer, the second is cleaner. Many vote
for the first - another Method in Object. Another well known Library
defines Object#should because they think of it to be nicer. By doing
this, we are slowly overloading the core-system. I like approach of
facets: they are a collection of such idioms, but they must be
switched on explicitly.
The question you have to answer for yourself when creating such a
method is: "Is it really that important?". Often I have the impression
that this question is often answered with "Yeah, its cool and its the
ruby way!"

On the other hand, those features are the ones that make the little
difference. Used correctly, open classes are a way to beautiful and
well constructed code.

It all comes boils to a matter of knowledge, experience and
discipline. We have got to be aware that many ruby developers don't
have all of those.

Greetings
Florian Gilcher <Skade>


James Gray

unread,
Feb 28, 2008, 9:36:02 AM2/28/08
to
On Feb 28, 2008, at 8:16 AM, Florian Gilcher wrote:

> Some time ago, many plugins had some implementation of
> String#constantize (better, worse, the same as the Rails version).
> This shows one thing:
> Plugin authors are not aware of everything the language has to offer.

Just to be clear, the Ruby programming "language" does not have a
method called String#constantize. It's provided by the Ruby on Rails
"framework."

James Edward Gray II


Florian Gilcher

unread,
Feb 28, 2008, 9:49:30 AM2/28/08
to
Yes,

sorry for not mentioning. I just found that many that where developing
plugins for Rails where patching things that didn't need to be patched
or hacked in the Framework.
Thanks for the clarification.

Florian Gilcher

av...@avdi.org

unread,
Feb 28, 2008, 9:50:26 AM2/28/08
to
That's what the poster said: "better, worse, the same as the Rails version".


--
Avdi

James Gray

unread,
Feb 28, 2008, 10:07:27 AM2/28/08
to
Please don't top post.

On 2/28/08, James Gray <ja...@grayproductions.net> wrote:

> On Feb 28, 2008, at 8:16 AM, Florian Gilcher wrote:
>
>> Some time ago, many plugins had some implementation of
>> String#constantize (better, worse, the same as the Rails version).
>> This shows one thing:
>> Plugin authors are not aware of everything the language has to offer.
>
> Just to be clear, the Ruby programming "language" does not have a
> method called String#constantize. It's provided by the Ruby on Rails
> "framework."

>
> On Feb 28, 2008, at 8:50 AM, av...@avdi.org wrote:
>
>> That's what the poster said: "better, worse, the same as the Rails
>> version".

Please reread the quote above where the poster hints that the method
is provided by a "language."

James Edward Gray II

Avdi Grimm

unread,
Feb 28, 2008, 11:00:05 AM2/28/08
to
On Thu, Feb 28, 2008 at 10:07 AM, James Gray <ja...@grayproductions.net> wrote:
> Please don't top post.

Sorry, that was posted from the GMail mobile interface.

--
Avdi

Florian Gilcher

unread,
Feb 28, 2008, 11:21:53 AM2/28/08
to

As i said, it was an accidential error and should read "Framework".
Programming Ruby for 5 years, I know the distinction ;).

Florian Gilcher

Robert Dober

unread,
Feb 28, 2008, 12:13:29 PM2/28/08
to
On Thu, Feb 28, 2008 at 6:51 AM, Joel VanderWerf
<vj...@path.berkeley.edu> wrote:
> Robert Dober wrote:
> > Just out of curiosity why does Class#freeze need to exist and cannot
> > be inherited from Object#freeze?
>
> Because Module#freeze is defined by ruby (so redefining Object#freeze
> would not have the desired effect in this case).
I was not criticizing your solution(1), I only wanted to know something.

Let me rephrase my question then, why Module#freeze what has it to do
in addition to Object#freeze
Just in case you happen to know.
Thx in advance

Cheers
Robert

>
> --
>
>
> vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407
>
>

--

Martin DeMello

unread,
Feb 28, 2008, 12:34:25 PM2/28/08
to
On Thu, Feb 28, 2008 at 6:16 AM, Florian Gilcher <f...@andersground.net> wrote:
>
> But, because we are lazy, lazy ruby programmers, we love our
> object.send syntax. So we implement a shorthand method. Another
> example is Object.in?(), often seen as a shorthand for
> some_collection.contains?(obj) (Im not sure, but this is called
> 'grief', afaik). The first is nicer, the second is cleaner. Many vote
> for the first - another Method in Object. Another well known Library
> defines Object#should because they think of it to be nicer. By doing
> this, we are slowly overloading the core-system.

And? There's nothing wrong with "overloading the core system" if the
end result is cleaner and more readable code. Personally, good ruby
code is all about expressiveness and readability, not proper OO
encapsulation and staying-out-of-the-core. The only real problem, as
you note, is that of conflicting extensions to the same core classes,
and care does need to be taken with that, but that's no reason to
throw the baby out with the bathwater.

One interesting thing to do is something I've seen in the Javascript
world - libraries that come with an option to install themselves in
core classes or stick to a namespace, so that you can either type
MyLib.do_something(object), or turn the option on and then do
object.do_something.

martin

Trans

unread,
Feb 29, 2008, 7:20:37 AM2/29/08
to

On Feb 24, 4:43 pm, Gary Wright <gwtm...@mac.com> wrote:

> Facets defines Hash#- based on [key,value] pairs and not keys. An
> argument can be made for either approach but you can't integrate code
> bases that have different expectations for Hash#-.

BTW, there is a reason for that. You can do:

ahash - otherhash.keys

T.

It is loading more messages.
0 new messages