What does 'Monkey Patching' exactly Mean in Ruby?

Hi –

On Sat, 3 Jan 2009, Robert D. wrote:

end
super.map{ |mn| mn.to_sym }
end
end
Class.include Version…

I’d be careful there. You’re making a class-wide (all instances of
Class) change. (include is private, but still :slight_smile: That could bite you
if you’re depending on instance_methods to return strings, which we
can legitimately do in 1.8.

class WhatEverOrMaybeEvenACoreClass
if instance_methods.include? :xxx then
raise IDoNotKnowWhatToDoError, “No I really don’t”
else
def xxx …
end
end
end

Any insights on IDoNotKnowWhatToDoError?

I guess you could go back to the #extend technique. I should add,
however, that even that technique isn’t bullet-proof. object#a might
call object#b, so if you override object#b in a module, object#a won’t
get the behavior it expects.

David


David A. Black / Ruby Power and Light, LLC
Ruby/Rails consulting & training: http://www.rubypal.com
Coming in 2009: The Well-Grounded Rubyist (The Well-Grounded Rubyist)

http://www.wishsight.com => Independent, social wishlist management!

If you’re really finding it necessary to create a whole class and a
method_missing apparatus to make gsub! chainable

This referred to the example of str += “foo”. I was simply elaborating
on my alternative proposal.

Part of the point of the #extend
technique is that it requires pin-pointing what you actually need

You’d have to make sure you are the only user of that object then,
wouldn’t you? You couldn’t really make such objects publicly
accessible? Could be fun to debug code that returns such objects from
a method.

Hi –

On Sat, 3 Jan 2009, Tom L. wrote:

This would return a normal string. You’d then have to extend those
more flexibility. With some extra work you could catch those cases
end

The extra indirection has its drawbacks of course.

If you’re really finding it necessary to create a whole class and a
method_missing apparatus to make gsub! chainable, it’s probably a sign
something needs to be rethought :slight_smile: Part of the point of the #extend
technique is that it requires pin-pointing what you actually need –
that is, which objects have to do what – so it’s definitely not the
same kind of solution as subclassing and/or changing existing classes.

The conclusion IMHO is twofold: (1) “monkey patching” is ok if you’re
the only user of your code (in which case it is okay to use a silly
name for that practice) or if the extensions are part of a well
documented supplementary library/framework where those extended
methods become some sort of standard. (2) Beware of people who are
proud of their monkey tactics.

I wouldn’t change gsub! globally even if I’m the only user of my code,
because it’s more a question of what other code I use (core Ruby
code, other libraries). They may be using gsub! as documented. (And of
course that’s just one example.)

David


David A. Black / Ruby Power and Light, LLC
Ruby/Rails consulting & training: http://www.rubypal.com
Coming in 2009: The Well-Grounded Rubyist (The Well-Grounded Rubyist)

http://www.wishsight.com => Independent, social wishlist management!

If you’re really finding it necessary to create a whole class and a
method_missing apparatus to make gsub! chainable

This referred to the example of str += “foo”. I was simply elaborating
on my alternative proposal.

Part of the point of the #extend
technique is that it requires pin-pointing what you actually need

You’d have to make sure you are the only user of that object then,
wouldn’t you? You couldn’t really make such objects publicly
accessible? Could be fun to debug code that returns such objects from
a method.

Hi –

On Sat, 3 Jan 2009, Tom L. wrote:

wouldn’t you? You couldn’t really make such objects publicly
accessible? Could be fun to debug code that returns such objects from
a method.

Right; I’m advocating being quite conservative about changing core
behaviors, and #extend is a relatively, but not absolutely,
conservative way. I like #extend in general – not just to avoid
making global changes but also just because it’s such a powerful way
to design an object. It often feels tighter to me than creating a new
class.

David


David A. Black / Ruby Power and Light, LLC
Ruby/Rails consulting & training: http://www.rubypal.com
Coming in 2009: The Well-Grounded Rubyist (The Well-Grounded Rubyist)

http://www.wishsight.com => Independent, social wishlist management!

Robert D. wrote:

Seriously now. Your warning is of course noteworthy, but this is the
price we have to pay for fixing 1.8 to 1.9 compatibility issues. So
the concern of yours is actually what I was doing here, deciding to go
for the 1.9 symbol version and allowing code to run with 1.8 too.

This begs the question, Has someone made a 1.9 emulation library for
1.8? (Emulation to the extent possible, that is.) The
symbols-instead-of-strings difference of Object#methods and the like are
easy to change. Instead of individuals hand-rolling their own
workarounds when issues arise, there should be a unified solution: a
ruby-1.9.gem for ruby 1.8.

On Fri, Jan 2, 2009 at 5:30 PM, David A. Black [email protected]
wrote:

I’d be careful there. You’re making a class-wide (all instances of
Class) change. (include is private, but still :slight_smile:
What??? Are you actually suggesting I should test my code ;)?

Seriously now. Your warning is of course noteworthy, but this is the
price we have to pay for fixing 1.8 to 1.9 compatibility issues. So
the concern of yours is actually what I was doing here, deciding to go
for the 1.9 symbol version and allowing code to run with 1.8 too. But
that was not really the issue of my post, maybe a new thread
discussing compatibility techniques would be interesting too.

Ok I see I have been as clear as ever :frowning: sorry.
My concern was, ok whenever I can do something which is aware of the
existence of a method your technique is a very sound starting point of
how to arrange things. But in the cases where I just add xxx and I am
not aware of any actual xxx, what to do if there already is one?
Probably the raise HelpMeException is pretty much the best we can do,
but I was hoping for some ideas on this topic.

Cheers
Robert

On Fri, Jan 2, 2009 at 10:12 PM, Mike G. [email protected]
wrote:

easy to change. Instead of individuals hand-rolling their own
workarounds when issues arise, there should be a unified solution: a
ruby-1.9.gem for ruby 1.8.
Well I am leaning myself a little bit out of the window, but I have
given some thoughts to it…
I will open a thread for this, ok?

2- Are “monkey patching” and “open classes” different terms for the same thing?

As far as I am concerned both terms refer to the same, but the stupid
“monkey patching” bears a negative connotation with it, and I refuse to
use it at all.

I believe people should be more open to ideas, and tagging a negative
meaning onto something will shoot down ideas that may happen “further
down the road” on it. The idea as such allows for more flexibility, and
why is it that the negative word of “Monkey patching” is used, but there
is no possitive association for this flexibility, which is a huge asset
for ruby? Most people who use the term monkey patching were coming from
java and python - in other words, people who do not even use ruby
seriously. (In fact, I blame a few diehard python bloggers for this.)

Hi –

On Sat, 3 Jan 2009, Robert D. wrote:

On Fri, Jan 2, 2009 at 5:30 PM, David A. Black [email protected] wrote:

I’d be careful there. You’re making a class-wide (all instances of
Class) change. (include is private, but still :slight_smile:
What??? Are you actually suggesting I should test my code ;)?

Seriously now. Your warning is of course noteworthy, but this is the
price we have to pay for fixing 1.8 to 1.9 compatibility issues. So
the concern of yours is actually what I was doing here, deciding to go
for the 1.9 symbol version and allowing code to run with 1.8 too.

It doesn’t allow it to run with 1.8, though, at least not safely. This
kind of thing is pretty common in 1.8:

instance_methods.each {|m| undef(m) unless m =~ /^__/ }

which would blow up if they were symbols.

But
that was not really the issue of my post, maybe a new thread
discussing compatibility techniques would be interesting too.
Ok I see I have been as clear as ever :frowning: sorry.
My concern was, ok whenever I can do something which is aware of the
existence of a method your technique is a very sound starting point of
how to arrange things. But in the cases where I just add xxx and I am
not aware of any actual xxx, what to do if there already is one?
Probably the raise HelpMeException is pretty much the best we can do,
but I was hoping for some ideas on this topic.

It’s a tough problem. I don’t think there’s any general solution,
since you can’t even use chaining since the two methods may have
nothing in common. I guess I tend to think that the case you’re
describing is the case where things have gone irreparably wrong.

David


David A. Black / Ruby Power and Light, LLC
Ruby/Rails consulting & training: http://www.rubypal.com
Coming in 2009: The Well-Grounded Rubyist (The Well-Grounded Rubyist)

http://www.wishsight.com => Independent, social wishlist management!

On 02/01/2009, David A. Black [email protected] wrote:

3- Is the following considered as monkey patching, or is it something

This was true, and quite deeply examined, well before the term “monkey
patching” came along to cloud the issue :slight_smile:

Adding a new method involves a kind of Prisoners’ Dilemma, situation,
where if either of us is the only one to add that particular method,
we “win”, but if we both do it, we lose. Changing methods, however,
can be done in a relatively low-impact way, if you chain them rather
than really changing them.

That is not entirely true. For one the array has each_with_index but I
could not find collect_with_index. If you look at the order of block
arguments passed by each_with_index and implement collect_with_index
the same way then if somebody else implements another one it must work
the same or they did it wrong :wink:

So if exact implementation of an extension can be logically deduced
from existing functionality adding it should not break anything,
Unfortunately it’s rarely possible.

str = “abc”.extend(MyGsubBang)

Among other advantages, this way of doing it forces you to think
carefully about the specific objects, and not throw too large a
blanket over what is actually a tiny problem (having one or two
objects that you want to behave different from the norm).

The problem with this approach is that either you want it on 1-2
objects and then it’s very local and the objects need not be strings
anyway, you can just make a special object for the purpose.

If you want strings that are used in particular piece of code to be
extended you can do it on the entry point(s). However, it’s tedious
and error-prone this way. (The concern about changing the strings is
not in place here if you gsub! them anyway, and you can dup)

The problem is that if the strings ever leave your code they are still
patched so in the end patching all strings in some way seems the
cleanest possible solution. Perhaps by adding a different method like
gsub!! or gsub!non_nil (assuming at least one is a valid identifier).

That’s why some sort of namespacing was requested so many times. It
makes patching in methods so much cleaner - only you would see the
methods you have added or modified.

Thanks

Michal

That is not entirely true. For one the array has each_with_index but I
could not find collect_with_index.

Then you should have written Array#collect_my_foo_objects_with_index, to
avoid a
collision.

Monkey patching is not for adding our own convenience methods, it is for
changing library code’s internal behavior. When someone else writes a
library
module that calls each_with_index, you might find it convenient to get
inside
each_with_index and twiddle with its behavior. This is not evil, it just
/is/,
and like all powerful abilities, we need to understand it and build good
guidelines for its fair use.

Hi –

On Sun, 4 Jan 2009, Michal S. wrote:

On 02/01/2009, David A. Black [email protected] wrote:

the same or they did it wrong :wink:

So if exact implementation of an extension can be logically deduced
from existing functionality adding it should not break anything,
Unfortunately it’s rarely possible.

That’s the dilemma :slight_smile: And that’s just a mild case; there’s also the
possibility that we’ll write same-named methods that clash and having
nothing to do with each other.

str = “abc”.extend(MyGsubBang)

Among other advantages, this way of doing it forces you to think
carefully about the specific objects, and not throw too large a
blanket over what is actually a tiny problem (having one or two
objects that you want to behave different from the norm).

The problem with this approach is that either you want it on 1-2
objects and then it’s very local and the objects need not be strings
anyway, you can just make a special object for the purpose.

This is a way to make a special object, or to make an object special.

If you want strings that are used in particular piece of code to be
extended you can do it on the entry point(s). However, it’s tedious
and error-prone this way. (The concern about changing the strings is
not in place here if you gsub! them anyway, and you can dup)

But if someone relies on gsub! returning nil under certain conditions
and it doesn’t, that’s a problem.

The problem is that if the strings ever leave your code they are still
patched so in the end patching all strings in some way seems the
cleanest possible solution. Perhaps by adding a different method like
gsub!! or gsub!non_nil (assuming at least one is a valid identifier).

That’s why some sort of namespacing was requested so many times. It
makes patching in methods so much cleaner - only you would see the
methods you have added or modified.

Absolutely. That’s really the only way out of all of this. It’s been
under serious discussion for a long time. Also, there are libraries at
RAA that already do it. The thing I’ve always found puzzling is that
everyone seems to want this functionality but I’ve literally never
seen code that uses those libraries (which doesn’t mean there isn’t
any, but I’m surprised that they aren’t that widely used considering
how much attention the issue has received).

David


David A. Black / Ruby Power and Light, LLC
Ruby/Rails consulting & training: http://www.rubypal.com
Coming in 2009: The Well-Grounded Rubyist (The Well-Grounded Rubyist)

http://www.wishsight.com => Independent, social wishlist management!

On Sat, Jan 3, 2009 at 2:54 AM, David A. Black [email protected]
wrote:

It doesn’t allow it to run with 1.8, though, at least not safely. This
kind of thing is pretty common in 1.8:

instance_methods.each {|m| undef(m) unless m =~ /^/ }
Very important point, I guess we can conclude two things from this
1st in this case it was a pretty bad idea to use symbols, using
strings would have been better
but not overriding instance_methods but by providing a
instance_methods_as_strings method (this is somehow superfluous as we
will see in the second point)
2nd we have to write a completely new class of Ruby programs for
1.8/1.9 and an example will be code like this
instance_methods.each{ … unless m.to_s =~ /^
/ }
Cheers
Robert

Hi –

On Sun, 4 Jan 2009, Phlip wrote:

That is not entirely true. For one the array has each_with_index but I
could not find collect_with_index.

Then you should have written Array#collect_my_foo_objects_with_index, to
avoid a collision.

Monkey patching is not for adding our own convenience methods, it is for
changing library code’s internal behavior.

That’s the tail wagging the dog, though. There’s no pre-determined
practice called “monkey patching” that delineates what can or should
be done. You can add convenience methods and also change internal
behavior. It doesn’t really matter, in the end, which one (or neither)
gets called “monkey patching”. (“Neither” would be my option of choice
:slight_smile:

David


David A. Black / Ruby Power and Light, LLC
Ruby/Rails consulting & training: http://www.rubypal.com
Coming in 2009: The Well-Grounded Rubyist (The Well-Grounded Rubyist)

http://www.wishsight.com => Independent, social wishlist management!

Hi –

On Sun, 4 Jan 2009, Robert D. wrote:

but not overriding instance_methods but by providing a
instance_methods_as_strings method (this is somehow superfluous as we
will see in the second point)
2nd we have to write a completely new class of Ruby programs for
1.8/1.9 and an example will be code like this
instance_methods.each{ … unless m.to_s =~ /^__/ }

Except…

$ ruby19 -ve ‘p :abc =~ /a/’
ruby 1.9.1 (2008-12-30 patchlevel-0 revision 21203) [i386-darwin9.5.0]
0

Symbols are (somewhat too, for my taste) string-like in 1.9. (I know
this is just an example, but it’s interesting to note this side point
I think.)

David


David A. Black / Ruby Power and Light, LLC
Ruby/Rails consulting & training: http://www.rubypal.com
Coming in 2009: The Well-Grounded Rubyist (The Well-Grounded Rubyist)

http://www.wishsight.com => Independent, social wishlist management!