Hi -- On Sun, 15 Nov 2009, Marnen Laibow-Koser wrote: > David A. Black wrote: > [...] >> I write class methods sometimes (I know those are singleton with an >> asterisk next to them, but still), > > Sometimes they're the right thing... > >> and I think that extending core >> objects with modules is a frequently overlooked and very powerful >> alternative to reopening core classes and adding methods. >> >> This kind of thing: >> >> class String >> def method_I_need_once_or_twice >> ... >> >> is almost always overkill. It's sort of the core-functionality >> counterpart of using global variables. > > True. (Even though I occasionally do this.) > >> Extending an object is a much >> more precise operation -- and has the additional merit, I find, of >> really making you think about whether it's worth bothering to the >> extend the object instead of working with what the object can already >> do. >> > > Agreed. But why is it worth extending an object instead of subclassing > it? > > In other words, > class SpecialString < String > def method_I_need_once_or_twice > ... > end > ... > @some_string = SpecialString.new(@some_string) > > seems to me like the right way to do this -- you can check if a given > String instance is a SpecialString or a plain String, or simply use > overriding and polymorphism for delegation. > > Yet, if I understand you correctly, you and James are claiming that it > is preferable to do > class << @some_string > def method_I_need_once_or_twice > end > > Do I understand correctly? If so, why? I hesitate to contradict such > experts as you and James, but I'm really not seeing the benefit. For > one thing, type-checking completely falls down with this pattern. > Polymorphism may or may not, depending on how it's implemented. And I > don't see a single advantage that we get in return for the loss of > type-checking. What am I missing? I'm not saying (and I don't think James would say) that this is a "winner-take-all" situation where we all have to choose one technique and do only that. But I think extending core objects is a very good way to add functionality to them. It sounds like by type-checking you mean class-checking (or ancestry-checking). It's kind of a circular argument, in the sense that if you decide that it's important to know an object's class because you're relying on that to tell you exactly what the object does, then it's bad if the object does other stuff (i.e., if its type diverges from its class). It's certainly possible to look at things that way, but it seems to me that it means you're fighting Ruby. The entire thrust of Ruby's object model is to put the focus on the objects rather than their classes. (Yes, I know that classes are objects :-) Them too -- which is why class methods are manifested as singleton methods on class objects, rather than some completely separate language-level construct.) Here's one of my favorite historical observations about Ruby, where ruby10 is the Ruby 1.0 interpreter: [dblack@ruby-versions ~]$ ruby10 -e 'puts "hi"'-e:1: NameError: undefined method `puts' for main(Object) [dblack@ruby-versions ~]$ ruby10 -e 'a = "hi"; class << a; def talk; print self + "!\n"; end; end; a.talk' hi! In other words, Ruby 1.0 had no puts statement... but it *did* have singleton classes. That's a great corrective to the perception I think some people have that singleton behaviors are some kind of meta-wizard-add-on complication to the language. They're not; the language was designed from the beginning to make it possible to engineer objects on an individual basis. I've heard people say that, while that's true, it's undisciplined to actually use any of these techniques. I disagree radically. Of course, I don't spend all that much of my time as a Ruby programmer writing singleton methods -- but I do regard the individual object as the center of gravity, and I regard classes largely as a convenience-macro for creating objects bundled with certain behaviors at their birth that may or may not represent what they do during their lifetimes. This is also why, in my book and in my training, I present singleton methods *first*, and classes second. (And I completely understand why Matt Neuberg introduces modules before classes[1] -- which I usually don't but it's an extremely intriguing idea.) Classes exist in Ruby, and no one is awarding points based on how many singleton methods one writes. But for me, anyway, the class part of the model floats on top of the real business, which is the objects. So I don't like to commit myself to having things break just because objects aren't aligned perfectly type-to-class. (There's more to say but that's long enough for now :-) David [1] http://www.apeth.com/rbappscript/02justenoughruby.html -- THE COMPLEAT RUBYIST, Ruby training with Black/Brown/McAnally! January 22-23, Tampa, Florica Info and registration at http://www.thecompleatrubyist.com -------------------------------------- My new job: http://tinyurl.com/yfpn9hz