On Thu, Oct 24, 2002 at 12:42:20PM +0900, William Djaja Tjokroaminata wrote:
> I think your example can be shortened to this:
> 
>   class S < String
>     def speak
>       puts "Hello, I contain: #{self}"
>     end
>   end  
>        
>   a = S.new("one")
>   puts "a.class = #{a.class}"                 # a.class = S
>   puts "(a+'two').class = #{(a+'two').class}" # (a+'two').class = String
> 
> Well, a "mechanical" explanation may be that class S calls the String
> class '+' method, which *always* creates a new object of class
> String.  But is it good from the "philosophical" point of view that
> 
>     Class_A + Class_B = Class_B (or even some other Class_C)
> 
> and not always Class_A?                              
> 
> (I would care less if the method is other than '+'...)

I also find this interesting, as it's a side-effect of subclassing I hadn't
thought about.

Somewhere deep in the innards of String#+ it is doing the equivalent of a
String.new; should it be doing a self.class.new instead?

Put more philosophically: is it the responsibility of a class author to
consider the requirements of possible future subclasses, in particular to
make sure that inherited methods have the 'right' behaviour in the context
of a subclass?

If not, then the subclass will end up having to wrap those methods - i.e.

  class S
    def +(arg)
      S.new(super)
    end
  end

That's ugly, and it seems like it was hardly worth inheriting the method in
the first place. [1]

The 'new' method which was inherited by S (or at least gives the appearance
of being inherited) doesn't need a wrapper though: S.new returns an S, not a
String. Perhaps that's why it's surprising that the inherited S#+ returns a
String not an S.

Regards,

Brian.

[1] That doesn't apply to _all_ inherited methods - e.g. the inherited '<=>'
is perfectly good - just methods which return String in this case