Forum: Ruby What does 'Monkey Patching' exactly Mean in Ruby?

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Yaser S. (Guest)
on 2008-12-27 17:18
(Received via mailing list)
According to Wikipedia, a monkey patch[1] is:

> a way to extend or modify the runtime code of dynamic languages [...]
> without altering the original source code.

The following statement from the same entry confused me:

> In Ruby, the term monkey patch was misunderstood to mean any dynamic
> modification to a class and is often used as a synonym for dynamically
> modifying any class at runtime.

I would like to know the exact meaning of monkey patching in Ruby. To be
more specific, I would like to know the answers to the following
questions:

1- What does "runtime code" refer to in Ruby?

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

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

class String
  def foo
    "bar"
  end
end

Regards,
Yaser S.

P.S. I originally posted this question on stackoverflow[2]. There are
some
good
answers over there, but I'm still kinda confused. I hope that someone in
the
Ruby
community can clarify this issue for me.

[1]: http://en.wikipedia.org/wiki/Monkey_patch
[2]:
http://stackoverflow.com/questions/394144/what-doe...
Robert D. (Guest)
on 2008-12-27 17:49
(Received via mailing list)
On Sat, Dec 27, 2008 at 4:17 PM, Yaser S. <removed_email_address@domain.invalid>
wrote:
>
> I would like to know the exact meaning of monkey patching in Ruby. To be
> more specific, I would like to know the answers to the following questions:
>
> 1- What does "runtime code" refer to in Ruby?
>
> 2- Are "monkey patching" and "open classes" different terms for the same
> thing?
I guess this is the critical point why the Wikipedia article says
"misunderstood"
as in Ruby even core classes are open MP just does not really mean
anything else for core classes
and your own classes or any other imported classes.
>
> 3- Is the following considered as monkey patching, or is it something else?
>
> class String
>  def foo
>    "bar"
>  end
> end

I would  consider it MP
> Regards,
> Yaser S.
>
> P.S. I originally posted this question on stackoverflow[2]. There are some
> good
> answers over there, but I'm still kinda confused. I hope that someone in the
> Ruby
> community can clarify this issue for me.
Hopefully ;)
Cheers
Robert
>
> [1]: http://en.wikipedia.org/wiki/Monkey_patch
> [2]:
> http://stackoverflow.com/questions/394144/what-doe...
>



--
Il computer non è una macchina intelligente che aiuta le persone
stupide, anzi, è una macchina stupida che funziona solo nelle mani
delle persone intelligenti.
Computers are not smart to help stupid people, rather they are stupid
and will work only if taken care of by smart people.

Umberto Eco
David A. Black (Guest)
on 2008-12-27 17:58
(Received via mailing list)
Hi --

On Sun, 28 Dec 2008, Yaser S. wrote:

>
> I would like to know the exact meaning of monkey patching in Ruby.

There's no exact meaning. Some people use it to mean re-opening core
classes; some people use it to mean re-opening core classes in an
incompetent, unsafe manner; some people use it as a way of indicating
that any time you re-open a core class, you shouldn't (which is a
well-intentioned but reductive position); some people use it to mean
re-opening non-core classes; and so on.

It's basically a negative, uninformative, rather silly term that has
nothing going for it. I personally don't use it. I'm a minority of
about one, though :-)


David
Phlip (Guest)
on 2008-12-27 18:00
(Received via mailing list)
Yaser S. wrote:

> 1- What does "runtime code" refer to in Ruby?

In WikiPedia's world, all applications have code that executes for the
end-user,
and support code - such as compilers, test files, code generators, etc.
Runtime
code is the former.

> 3- Is the following considered as monkey patching, or is it something else?
>
> class String
>   def foo
>     "bar"
>   end
> end

No, that is simply extending the class with a new method. Ruby classes
are
always open for extension, and the article you cited implied the
misunderstanding was that is monkey patching. It is not.

This is monkey patching:

   class String
     def length
       42
     end
   end

The method .length already existed, but we had our way with it. And this
example
shows why MP is kind'a dangerous. Ruby has no mechanism to allow only
our own
modules to see our patches. My example gives all library code a bogus
string
length, and our runtime code would not last very long...

Unfortunately for those who fear Monkey Patching, many Ruby libraries
rely on
it. They are released rough-and-ready, before any serious effort to
detect where
to install "hooks" (look up "Abstract Template Design Pattern"). So to
get
anything done in a big Ruby application, your monkeys will be frequently
climbing up your inheritance trees and patching the code they find
there!

> [1]: http://en.wikipedia.org/wiki/Monkey_patch

WP is full of biases and points-of-view; use it carefully!!
Robert K. (Guest)
on 2008-12-27 18:05
(Received via mailing list)
On 27.12.2008 16:17, Yaser S. wrote:
>> modification to a class and is often used as a synonym for dynamically
>> modifying any class at runtime.
>
> I would like to know the exact meaning of monkey patching in Ruby. To be
> more specific, I would like to know the answers to the following questions:

<disclaimer>I am by no means authoritative for the subject.</disclaimer>

> 1- What does "runtime code" refer to in Ruby?

It refers to the code that is shipped with the interpreter or other
runtime system (e.g. String, Hash, Array, Fixnum and the like).  Usually
a lot other code depends on this and a monkey patch has a certain
potential to wreck havoc on the whole application. :-)

> 2- Are "monkey patching" and "open classes" different terms for the same
> thing?

Yes, of course.  "Open classes" is a general concept, while "monkey
patching" is a methodology (at least something procedural).  You can use
"open classes" to do "monkey patching" - but there are other tools as
well that you can use to do it (e.g. you could try to overwrite code in
memory or in C change the pointer of a basic function like strlen).

> 3- Is the following considered as monkey patching, or is it something else?
>
> class String
>   def foo
>     "bar"
>   end
> end

I would not call this "monkey patching" because although you modify a
core class you do not modify a _core functionality_.  Most of the time I
have seen "monkey patching" denote a change to core functionality with
potentially far reaching consequences, e.g. this would rather be a
monkey patch

class Object
   def to_s
     "boom!"
   end
end

because it has potential to make certain things work but also break *a
lot* of code.

Cheers

  robert
Robert K. (Guest)
on 2008-12-27 18:50
(Received via mailing list)
2008/12/27 David A. Black <removed_email_address@domain.invalid>:

> It's basically a negative, uninformative, rather silly term that has
> nothing going for it. I personally don't use it. I'm a minority of
> about one, though :-)

I'd say "about two". :-)

robert
James B. (Guest)
on 2008-12-27 20:19
(Received via mailing list)
David A. Black wrote:

> It's basically a negative, uninformative, rather silly term that has
> nothing going for it. I personally don't use it. I'm a minority of
> about one, though :-)

Minority of at least two.
Martin DeMello (Guest)
on 2008-12-27 23:43
(Received via mailing list)
On Sat, Dec 27, 2008 at 8:49 PM, Robert K.
<removed_email_address@domain.invalid> wrote:
> 2008/12/27 David A. Black <removed_email_address@domain.invalid>:
>
>> It's basically a negative, uninformative, rather silly term that has
>> nothing going for it. I personally don't use it. I'm a minority of
>> about one, though :-)
>
> I'd say "about two". :-)

Four at the least :)

m.
James B. (Guest)
on 2008-12-28 01:16
(Received via mailing list)
Martin DeMello wrote:
> On Sat, Dec 27, 2008 at 8:49 PM, Robert K.
> <removed_email_address@domain.invalid> wrote:
>> 2008/12/27 David A. Black <removed_email_address@domain.invalid>:
>>
>>> It's basically a negative, uninformative, rather silly term that has
>>> nothing going for it. I personally don't use it. I'm a minority of
>>> about one, though :-)
>> I'd say "about two". :-)
>
> Four at the least :)

Cool!  We can be a gang!




--
James B.

www.happycamperstudios.com   - Wicked Cool Coding
www.jamesbritt.com           - Playing with Better Toys
www.ruby-doc.org             - Ruby Help & Documentation
www.rubystuff.com            - The Ruby Store for Ruby Stuff
marc (Guest)
on 2008-12-28 13:17
(Received via mailing list)
David A. Black said...
> >
> well-intentioned but reductive position); some people use it to mean
> re-opening non-core classes; and so on.

My brain is fuddled today recovering from flu, but what do you mean by
"reopening"?
David A. Black (Guest)
on 2008-12-28 13:19
(Received via mailing list)
Hi --

On Sun, 28 Dec 2008, marc wrote:

>>> The following statement from the same entry confused me:
>> that any time you re-open a core class, you shouldn't (which is a
>> well-intentioned but reductive position); some people use it to mean
>> re-opening non-core classes; and so on.
>
> My brain is fuddled today recovering from flu, but what do you mean by
> "reopening"?

Like this:

   class Array
     def my_new_method
     end
   end

where I'm reopening the core Array class and adding and/or overriding
methods in it.


David
marc (Guest)
on 2008-12-28 14:07
(Received via mailing list)
David A. Black said...
> >>>
> >>
> Like this:
>
>    class Array
>      def my_new_method
>      end
>    end
>
> where I'm reopening the core Array class and adding and/or overriding
> methods in it.

Okay, so reopening is extending or overriding (a method of) a core
class. Good to know the lingo.

And I concur with your earlier assertion regarding the MP term:

  It's basically a negative, uninformative, rather silly term that has
  nothing going for it.
Dave B. (Guest)
on 2008-12-28 14:09
Robert K. wrote:
> class Object
>    def to_s
>      "boom!"
>    end
> end

I CAN HAZ LULZ!1!!11!

Dave
Gavin S. (Guest)
on 2008-12-29 11:31
(Received via mailing list)
> >> It's basically a negative, uninformative, rather silly term that has
> >> nothing going for it. I personally don't use it. I'm a minority of
> >> about one, though :-)
>
> > I'd say "about two". :-)
>
> Four at the least :)
>
> m.

Based on the evidence before you, Martin, you can only conclude "Three
at the least".  James didn't declare his hand.

Cheers,
Gavin
Yaser S. (Guest)
on 2008-12-29 17:56
(Received via mailing list)
Thank you for your answers, everyone. They were really informative.

On Sat, Dec 27, 2008 at 6:56 PM, David A. Black 
<removed_email_address@domain.invalid>
wrote:

>
> There's no exact meaning.
>
>
I couldn't agree more. It almost seems like every one has his own
special
understanding of the term. But I guess that this isn't always a bad
thing.
After all, in a community of more than one person, there will always be
a
thing that the community can't agree upon. :P

On Sun, Dec 28, 2008 at 2:16 AM, James B. <removed_email_address@domain.invalid>
wrote:

>
> Cool!  We can be a gang!
>
>
Count me in! - but I still think that the term 'monkey patching' is
cooler/funkier than 'open classes' :P

Regards,
Yaser
Jörg W Mittag (Guest)
on 2009-01-02 10:23
(Received via mailing list)
Phlip wrote:
> Yaser S. wrote:
>> 3- Is the following considered as monkey patching, or is it something else?
>>
>> class String
>>   def foo
>>     "bar"
>>   end
>> end
>
> No, that is simply extending the class with a new method.

Ah, but that's the interesting part: how do you know that somebody
else didn't already add a String#foo method? In that case, it *would*
be monkey patching. Even worse: which of the two methods would be
considered monkey patching and which one wouldn't, would depend
entirely on the *load order* of those two snippets of code.

That's why I don't think distinguishing between adding and changing
methods makes sense: either both are monkey patching or neither are.

jwm
Phlip (Guest)
on 2009-01-02 10:24
(Received via mailing list)
> Ah, but that's the interesting part: how do you know that somebody
> else didn't already add a String#foo method?

That's why it's not "elegantly patching with surgical precision".

You weren't the monkey - for publishing such a silly method. _They_
were!

(Stating this as a guideline - if it's a vanilla method name like
'.length',
it's a monkey patch, and if it's application-specific you should give it
a weird
name, like '.__my_boss_my_app_length'.)
David A. Black (Guest)
on 2009-01-02 14:43
(Received via mailing list)
Hi --

On Fri, 2 Jan 2009, Jörg W Mittag wrote:

>> No, that is simply extending the class with a new method.
>
> Ah, but that's the interesting part: how do you know that somebody
> else didn't already add a String#foo method? In that case, it *would*
> be monkey patching. Even worse: which of the two methods would be
> considered monkey patching and which one wouldn't, would depend
> entirely on the *load order* of those two snippets of code.
>
> That's why I don't think distinguishing between adding and changing
> methods makes sense: either both are monkey patching or neither are.

This was true, and quite deeply examined, well before the term "monkey
patching" came along to cloud the issue :-)

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.

I'll put in a plug for what I believe is by far the safest way to
extend core functionality, namely #extend.  A classic case is the
desire to have #gsub! not return nil when the string doesn't change.

   module MyGsubBang
     def gsub!(*args, &block)
       super(*args, &block) || self
     end
   end

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


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!
Robert D. (Guest)
on 2009-01-02 17:12
(Received via mailing list)
On Fri, Jan 2, 2009 at 1:42 PM, David A. Black 
<removed_email_address@domain.invalid>
wrote:

>  str = "abc".extend(MyGsubBang)
This indeed is a very sensible and elegant way to do things.

The true werewolf of dynamic extension (I am happy with MP but there
seems to be a consensus against that term...) however is this case

# first I am using what I have just learned from David :-P
module VersionIndependentInstanceMethods
   def instance_methos *args, &blk
      super.map{ |mn| mn.to_sym }
   end
end
Class.include Version...

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?

Cheers
Robert
David A. Black (Guest)
on 2009-01-02 18:32
(Received via mailing list)
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 :-) 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 (http://manning.com/black2)

http://www.wishsight.com => Independent, social wishlist management!
Tom L. (Guest)
on 2009-01-02 18:34
(Received via mailing list)
>    module MyGsubBang
>      def gsub!(*args, &block)
>        super(*args, &block) || self
>      end
>    end
>
>    str = "abc".extend(MyGsubBang)

str += "1"

This would return a normal string. You'd then have to extend those
strings again and again. Please correct me if I'm wrong but IMHO this
approach brings little advantage over defining a subclass of String:

class MyString < String
    ...
end

str = MyString.new("abc")

This creates a copy of "abc" in this particular case but provides IMHO
more flexibility. With some extra work you could catch those cases
where the function returns a new string, eg something in the line of:

class MyString < BasicObject

    YOUR METHODS HERE

    def method_missing(...)
        ...
    end

end

The extra indirection has its drawbacks of course.

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.
David A. Black (Guest)
on 2009-01-02 18:47
(Received via mailing list)
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 :-) 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 (http://manning.com/black2)

http://www.wishsight.com => Independent, social wishlist management!
Tom L. (Guest)
on 2009-01-02 20:50
(Received via mailing list)
> 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.
Tom L. (Guest)
on 2009-01-02 20:51
(Received via mailing list)
> 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.
David A. Black (Guest)
on 2009-01-02 21:34
(Received via mailing list)
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 (http://manning.com/black2)

http://www.wishsight.com => Independent, social wishlist management!
Robert D. (Guest)
on 2009-01-02 22:08
(Received via mailing list)
On Fri, Jan 2, 2009 at 5:30 PM, David A. Black 
<removed_email_address@domain.invalid>
wrote:

> 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
Mike G. (Guest)
on 2009-01-02 23:12
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.
Robert D. (Guest)
on 2009-01-02 23:23
(Received via mailing list)
On Fri, Jan 2, 2009 at 10:12 PM, Mike G. <removed_email_address@domain.invalid>
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?
Robert H. (Guest)
on 2009-01-03 00:24
> 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.)
David A. Black (Guest)
on 2009-01-03 03:56
(Received via mailing list)
Hi --

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

> On Fri, Jan 2, 2009 at 5:30 PM, David A. Black <removed_email_address@domain.invalid> 
wrote:
>
>> 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.

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!
Michal S. (Guest)
on 2009-01-03 19:06
(Received via mailing list)
On 02/01/2009, David A. Black <removed_email_address@domain.invalid> 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 :-)
>
>  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 ;-)

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
David A. Black (Guest)
on 2009-01-03 20:39
(Received via mailing list)
Hi --

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

> On 02/01/2009, David A. Black <removed_email_address@domain.invalid> wrote:

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

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

http://www.wishsight.com => Independent, social wishlist management!
Phlip (Guest)
on 2009-01-03 20:55
(Received via mailing list)
> 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.
Robert D. (Guest)
on 2009-01-03 21:21
(Received via mailing list)
On Sat, Jan 3, 2009 at 2:54 AM, David A. Black 
<removed_email_address@domain.invalid>
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
David A. Black (Guest)
on 2009-01-03 21:53
(Received via mailing list)
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 (http://manning.com/black2)

http://www.wishsight.com => Independent, social wishlist management!
David A. Black (Guest)
on 2009-01-03 22:02
(Received via mailing list)
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
:-)


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!
This topic is locked and can not be replied to.