Section 2.17. Appending an Item Onto a String


2.16. Implicit and Explicit Conversion

At first glance, the to_s and to_str methods seem confusing. They both convert an object into a string representation, don't they?

There are several differences. First, any object can in principle be converted to some kind of string representation; that is why nearly every core class has a to_s method. But the to_str method is never implemented in the core.

As a rule, to_str is for objects that are really very much like stringsthat can "masquerade" as strings. Better yet, think of the short name to_s as being explicit conversion and the longer name to_str as being implicit conversion.

You see, the core does not define any to_str methods (that I am aware of). But core methods do call to_str sometimes (if it exists for a given class).

The first case we might think of is a subclass of String; but in reality, any object of a subclass of String already "is-a" String, so to_str is unnecessary there.

Here is a real-life example. The Pathname class is defined for convenience in manipulating filesystem pathnames (for example, concatenating them). However, a pathname maps naturally to a string (even though it does not inherit from String).

require 'pathname' path = Pathname.new("/tmp/myfile") name = path.to_s   # "/tmp/myfile" name = path.to_str # "/tmp/myfile" (So what?) # Here's why it matters... heading = "File name is " + path puts heading       # "File name is /tmp/myfile"


Notice that in the preceding code fragment, we take a string "File name is" and directly append a path onto it. Normally this would give us a runtime error, since the + operator expects the second operand to be another string. But because Pathname has a to_str method, that method is called. A Pathname can "masquerade" as a String; it is implicitly converted to a String in this case.

In real life, to_s and to_str usually return the same value; but they don't have to do so. The implicit conversion should result in the "real string value" of the object; the explicit conversion can be thought of as a "forced" conversion.

The puts method calls an object's to_s method in order to find a string representation. This behavior might be thought of as an implicit call of an explicit conversion. The same is true for string interpolation. Here's a crude example:

class Helium   def to_s     "He"   end   def to_str     "helium"   end end e = Helium.new print "Element is " puts e                    # Element is He puts "Element is " + e    # Element is helium puts "Element is #{e}"    # Element is He


So you can see how defining these appropriately in your own classes can give you a little extra flexibility. But what about honoring the definitions of the objects passed into your methods?

For example, suppose that you have a method that is "supposed" to take a String as a parameter. Despite our "duck typing" philosophy, this is frequently done and is often completely appropriate. For example, the first parameter of File.new is "expected" to be a string.

The way to handle this is simple. When you expect a string, check for the existence of to_str and call it as needed.

def set_title(title)   if title.respond_to? :to_str     title = title.to_str   end   # ... end


Now, what if an object doesn't respond to to_str? We could do several things. We could force a call to to_s; we could check the class to see whether it is a String or a subclass thereof; or we could simply keep going, knowing that if we apply some meaningless operation to this object, we will eventually get an ArgumentError anyway.

A shorter way to do this is

title = title.to_str rescue title


which depends on an unimplemented to_str raising an exception. The rescue modifiers can of course be nested:

title = title.to_str rescue title.to_s rescue title # Handle the unlikely case that even to_s isn't there


Implicit conversion would allow you to make strings and numbers essentially equivalent. You could do this:

class Fixnum   def to_str     self.to_s   end end str = "The number is " + 345     # The number is 345


However, I don't recommend this sort of thing. There is such a thing as "too much magic"; Ruby, like most languages, considers strings and numbers to be different, and I believe that most conversions should be explicit for the sake of clarity.

Another thing to remember: There is nothing magical about the to_str method. It is intended to return a string, but if you code your own, it is your responsibility to see that it does.




The Ruby Way(c) Solutions and Techniques in Ruby Programming
The Ruby Way, Second Edition: Solutions and Techniques in Ruby Programming (2nd Edition)
ISBN: 0672328844
EAN: 2147483647
Year: 2004
Pages: 269
Authors: Hal Fulton

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net