Ruby: to_s vs. to_str
I've experienced a bit of confusion when it comes to Ruby's to_s vs. to_str methods. This site says:
to_str is an implicit cast, whereas to_s is an explicit cast.
...
If you’re having a hard time remembering which is which, I would remember that there is a reason that to_s is shorter. First, it implies that the object isn’t really much of a string, so we’re only using the first letter ’s’. Also, to_s is shorter because more objects will have to_s methods, so you’ll end up typing it more frequently.With to_str, we’re tagging an object as much closer to being a string, so we give it the first three letters. It’s almost half of a string!
That's about as vague as you can get. It's also a bit confusing because although to_s is supposedly an "explicit class", some built-in methods call it implicitly (e.g. puts).
Programming Ruby, in the Duck Typing chapter (page 372) says:
[to_i and to_s] are not particularly strict: if an object has some kind of decent representation as a string, for example, it will probably have a to_s method...
[to_int and to_str] are strict conversion functions: you implement them only if you object can naturally be used every place a string or an integer could be used.
That's more helpful, but the notion of "strict" vs. "not very strict" certainly isn't very precise. For any given built-in method, does it use to_s or to_str? That's what I'd like to know.
I wrote a test:
# to_s vs. to_str test module String_Test def initialize(arg) @test = arg end def to_s puts 'to_s called!' 'to_s ' + @test end def to_str puts 'to_str called!' 'to_str ' + @test end end class Both include String_Test end class No_to_s include String_Test undef_method :to_s end class No_to_str include String_Test undef_method :to_str end class Neither include String_Test undef_method :to_s undef_method :to_str end [Both, No_to_s, No_to_str, Neither].each do |curr_class| puts puts '=' * 40 puts curr_class.to_s puts '=' * 40 t = curr_class.new('foo') [ %q{t }, %q{p t }, %q{print t, "\n" }, %q{puts t }, %q{puts t.to_s }, %q{puts t, t }, %q{"#{t}" }, %q{puts "#{t}" }, %q{puts t.to_str }, %q{puts 'ADDING:' + t }, %q{'123'.split(t) }, %q{Dir.glob(t) }, %q{File.new(t) }, %q{/./.match(t) }, %q{nil.respond_to?(t) }, ].each do |code| puts 'RUNNING: ' + code begin eval code rescue Exception => e puts "ERROR: #{e}" end puts '-' * 20 end end
The output (which are long and I won't paste here) shows that:
- print, puts and string interpolation use "to_s". Mostly everything else (glob, split, match, string concatenation) uses to_str.
- Defining to_str will NOT define to_s for you, and vice versa. Going by the vague intuitive descriptions given above, I'd almost have expected methods that use to_s to know enough to fall back to using to_str. If an object is inherently in some sense a String, why would print/puts output anything BUT the String interpretation of the object? If we're including this to_s / to_str convention in the language, you'd think that an implicit to_s -> to_str fallback would be there too.
- respond_to? fails. This is because it expects a Symbol. Strings have a to_sym method, but my class doesn't. So even though to_str means your class "can naturally be used every place a string can be used", my class obviously is NOT really a string, since it doesn't inherit all of Strings methods. So there are plenty of places a String "can be used" that my class cannot, for various definitions of "can be used".
So I imagine if you're writing your own class which takes arguments that you plan to coerce into Strings, you should use to_s only if you're outputting or String-interpolating a value, and use to_str if you're doing anything substantial. But this really is a bit vague for my liking.

I would look at it this way:
to_s is a tool to output human readable status/debug info
to_str is expected to be program readable.