Eric Hodel wrote:
> On Aug 7, 2006, at 3:30 PM, Daniel Schierbeck wrote:
>> Eric Hodel wrote:
>>> On Aug 6, 2006, at 7:55 AM, Daniel Schierbeck wrote:
>>>> I'd do it like this:
>>>>
>>>>   class SomeClass
>>>>     def foo(obj)
>>>>       str = obj.to_str
>>> Don't call to_str, call to_s.
>>>>       puts str + str # or `str * 2'
>>>>       puts str.reverse
>>>>     end
>>>>   end
>>>>
>>>> Though I know some very smart people on this list disagree with me.
>>> Only because you call to_str.  This is not the reason it exists.
>>
>> I favor using #to_str when I want to treat an object like a string. 
>> Practically all classes implement #to_s, so it's not really a type 
>> restriction. We're trying to solve two different problems -- I want to 
>> let the caller know if he sent the wrong kind of object as an 
>> argument. That's type checking. If you want to convert any object 
>> received to a string, then we're talking type conversion, which I 
>> think should be left to the caller in many cases. But that's just my 
>> humble opinion, of course.
> 
> #to_str is not for type conversion.  It exists for classes that duck 
> type completely to String and is called when a C string is needed by a 
> method in String to improve performance.  In other words, #to_str should 
> only be implemented on objects that are already "Strings".

Exactly my point. I think we're misunderstanding each other here; if you 
have an object that is a representation of a string, say

   # Bad example, but hey...
   class Name
     attr_accessor :first, :last

     def initialize(first, last)
       @first, @last = first, last
     end
   end

Then it's okay for it to have #to_str, e.g.

     def to_str
       "#{first} #{second}"
     end

My own logic is this: if an object is a natural string, but with *more* 
information, then it can have #to_str. Otherwise, stick to #to_s.

A much better example is the one brought up on the list not long ago:

   class RomanNumeral
     def initialize(num)
       @num = num.to_int
     end

     # this really is an integer
     def to_int
       @num
     end

     # but there's not much sense in manipulating
     # it as a string
     def to_s
       ...
     end
   end

If it were for a real application, I'd just implement an 
Integer#to_roman method, but I still think this is a good example.

> #to_s is for type conversion.  Trust your users to provide a meaningful 
> #to_s.  Don't force them to inappropriately implement #to_str.

I agree wholeheartedly. I'm just bad at writing.