Hi --
Thanks to all the respondents.
The confusion stemmed from some of the inconsistency that is around the
to_str usage within Ruby.
See this below.
class A
def to_str
"hello"
end
def to_s
"bye"
end
end
# Note to_s and to_str return different strings.
irb(main):018:0> "xyz"+A.new
=> "xyzhello"
Good, as to_str is called when it is 'expected' that arg to + is going to be
a string.
irb(main):019:0> "hello" == A.new
=> false
This is fine too as David pointed out, one could argue though because there
already is a equal? but anyway....lets move on.
I'm digging around in the source to figure out the == behavior. Here's
the method:
static VALUE
rb_str_equal(str1, str2)
VALUE str1, str2;
{
if (str1 == str2) return Qtrue;
if (TYPE(str2) != T_STRING) {
if (!rb_respond_to(str2, rb_intern("to_str"))) {
return Qfalse;
}
return rb_equal(str2, str1);
}
if (RSTRING(str1)->len == RSTRING(str2)->len &&
rb_str_cmp(str1, str2) == 0) {
return Qtrue;
}
return Qfalse;
}
I haven't quite figured out what the point is of testing to see
whether str2 responds to "to_str", since even if it does, to_str isn't
called. But I might just have to keep following the trail....
Then see
irb(main):020:0> A.new.upcase
NoMethodError: undefined method `upcase' for hello:A
from (irb):20
Again since A.new is not a String a method_missing is called etc.
Bear with me a little more 
irb(main):021:0> "hellooo".include? A.new
=> true
This is good because the argument is expected to be a string.
I believe the to_str thing is always about arguments. The object A.new
is not just going to act like a string; you can't call String instance
methods on it (like upcase). It's only going to provide its to_str
representation when it's an argument, as in include? .
Now see this
irb(main):022:0> "a" << A.new
=> "ahello"
OK so now Ruby used the string representation from to_str *not* to_s
Now is it true that *only* object of class String are expected to be
appended to a string using << operator, hence the coercion?
Not quite -
irb(main):023:0> "a" << 1
=> "a\001"
While of course -
irb(main):025:0> 1.to_str
NoMethodError: undefined method `to_str' for 1:Fixnum
But of course -
irb(main):038:0> 1.to_s
=> "1"
So is it the case that when a string is "expected" then a to_str is tried if
not found then to_s is tried, as can be deduced from the last two operations
above? But then of course the following would fail -
It's not exactly that. Have a look at this and you'll see:
irb(main):004:0> "abc" << 1
=> "abc\001"
irb(main):005:0> "abc" << 100
=> "abcd"
irb(main):006:0> "abc" << 10
=> "abc\n"
This operation doesn't involve to_s or to_str, so it doesn't tell you
anything about how they work. Your next example answers the question,
though: to_s does not serve as a fall-back for to_str.
David
···
On Tue, 14 Aug 2007, Nasir Khan wrote:
--
* Books:
RAILS ROUTING (new! http://www.awprofessional.com/title/0321509242\)
RUBY FOR RAILS (http://www.manning.com/black\)
* Ruby/Rails training
& consulting: Ruby Power and Light, LLC (http://www.rubypal.com)