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