From: "David A. Black" Date: 2009-01-04T03:37:54+09:00 Subject: Re: What does 'Monkey Patching' exactly Mean in Ruby? Hi -- On Sun, 4 Jan 2009, Michal Suchanek wrote: > On 02/01/2009, David A. Black wrote: >> 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. 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. >> 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). >> > > 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!