Defining to_s works oddly?

Hi all. Am I the only one that finds it odd that if I define a to_s function for a class, that if I do:
puts obj

I won't get errors, but if I try something like:
s = String.new
s += obj

I get a 'can not convert a <class type>' into String type error'...

It's no prob to write obj.to_s, it's just I expected the first version to call to_s automatically...

Martin

PS for clarity, my complete error producing example is as follows:

class Animal

  def initialize(name)
    fail "name is nil" if name.nil?

    @name = name
  end

  def to_s
    "#{@name}"
  end

end

c = Animal.new('Snoes')

puts c

puts "substituted in a string literal: #{c}"

s = String.new
s += c

#puts s

Hi all. Am I the only one that finds it odd that if I define a to_s function for a class, that if I do:
puts obj

I won't get errors, but if I try something like:
s = String.new
s += obj

For that, you need the duck typed version of the method, to_str()...

class Animal

def initialize(name)
   fail "name is nil" if name.nil?

   @name = name
end

def to_s
   "#{@name}"
end

alias_method :to_str, :to_s

end

c = Animal.new('Snoes')

puts c

puts "substituted in a string literal: #{c}"

s = String.new
s += c

James Edward Gray II

···

On Jul 26, 2005, at 7:48 AM, Martin Elzen wrote:

Hi Martin,

Am I the only one that finds it odd that if I define a
to_s function for a class, that if I do

   puts obj

I won't get errors, but if I try something like

   s = String.new
   s += obj

I get a [TypeError]

You're probably not the only one. The reason why ‘puts’
converts its argument using ‘to_s’ but String#+ doesn't is
far from obvious.

It's no prob to write obj.to_s, it's just I expected the
first version to call to_s automatically...

As James Edward Gray II quoted Why saying, “to_str is an
implicit cast, whereas to_s is an explicit cast,” and you
could probably redefine String#+ to perform the explicit
cast instead of the implicit with no problems resulting.

But I wouldn't do that. There is a significant difference
between ‘"#{foo}"’ (or ‘puts foo’) and ‘"bar" + foo’:
The former *must* result in a string, whereas the latter
could reasonably result in something other than a string.

Consider these two expressions:

         "1" + 2 and 1 + "2"

Current Ruby behavior is to reject both with type errors.
See, Fixnum#+ implicitly casts its argument into a number,
and String#+ implicitly casts its argument into a string,
but neither argument can be implicitly casted that way.

[Again, the term “implicit cast” is not an exact description
of what happens, but rather a shorter way of saying “convert
if possible and fail otherwise.”]

You could make either method use an explicit cast instead of
an implicit, but if you make both explicit you would be in
the following weird situation:

   "1" + 2 #=> "12"

   1 + "2" #=> 3

Assuming you agree that this asymmetry is unacceptable,
the question is, which cast should take precedence?

Perl avoids this ambiguity by letting "1" == 1, so that

   "1" + 2 == 1 + "2" == "3" == 3.

Ruby avoids it by requiring an explicit cast:

   "1" + 2.to_s #=> "12"

   1.to_s + "2" #=> "12"

   1 + "2".to_i #=> 3

   "1".to_i + 2 #=> 3

I know this message doesn't provide any solutions, but I
hope it can help you accept Ruby's behavior as reasonable
(something I consider very important for trust reasons).

···

--
Daniel Brockman <daniel@brockman.se>

    So really, we all have to ask ourselves:
    Am I waiting for RMS to do this? --TTN.

I'm curious about that... why the two methods, to_s/to_str? I know
it's been discussed before, and I *think* I understood it then, but
I've since forgotten and there are probably others who haven't heard
the explanation before.

Jacob Fugal

···

On 7/26/05, James Edward Gray II <james@grayproductions.net> wrote:

For that, you need the duck typed version of the method, to_str()...

To make a rough guess? So that you can say 'this is my human readable
version' (to_s) vs. 'this is how you convert me to a string' (to_str).

···

On 7/26/05, Jacob Fugal <lukfugl@gmail.com> wrote:

On 7/26/05, James Edward Gray II <james@grayproductions.net> wrote:
> For that, you need the duck typed version of the method, to_str()...

I'm curious about that... why the two methods, to_s/to_str? I know
it's been discussed before, and I *think* I understood it then, but
I've since forgotten and there are probably others who haven't heard
the explanation before.

Jacob Fugal

--
Brad Wilson
http://www.dotnetdevs.com/
http://www.agileprogrammer.com/dotnetguy/

Peter: "Oh my god, Brian, there's a message in my Alphabits. It says,
'Oooooo.' "
Brian: "Peter, those are Cheerios."
- Family Guy

Why discusses that a little at:

http://whytheluckystiff.net/articles/rubyOneEightOh.html

Here's probably the most relevant quote:

"So why not use to_s? Because to_s coerces objects into strings. So, to_str is an implicit cast, whereas to_s is an explicit cast."

Hope that helps.

James Edward Gray II

···

On Jul 26, 2005, at 10:18 AM, Jacob Fugal wrote:

On 7/26/05, James Edward Gray II <james@grayproductions.net> wrote:

For that, you need the duck typed version of the method, to_str()...

I'm curious about that... why the two methods, to_s/to_str? I know
it's been discussed before, and I *think* I understood it then, but
I've since forgotten and there are probably others who haven't heard
the explanation before.