What does 'Monkey Patching' exactly Mean in Ruby?

T

Tom Link

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.
 
T

Tom Link

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.
 
D

David A. Black

Hi --

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


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.

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 (http://manning.com/black2)

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

Robert Dober

I'd be careful there. You're making a class-wide (all instances of
Class) change. (include is private, but still :)
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.
<snip>
Ok I see I have been as clear as ever :( 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
 
M

Mike Gold

Robert said:
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.
 
R

Robert Dober

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.
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?
 
M

Marc Heiler

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.)
 
D

David A. Black

Hi --

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 :( 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 (http://manning.com/black2)

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

David A. Black

Hi --

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 ;-)

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 :) 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.
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 (http://manning.com/black2)

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

Phlip

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.
 
R

Robert Dober

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
 
D

David A. Black

Hi --

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 =~ /^__/ }

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 (http://manning.com/black2)

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

David A. Black

Hi --

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
:)


David

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

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

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,143
Latest member
SterlingLa
Top