Home > Articles > Programming > Ruby

  • Print
  • + Share This
This chapter is from the book

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, however. 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 strings—that 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. 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.

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 if title.respond_to?(:to_str)

which replaces the value of title only if it has a to_str method.

Double-quoted string interpolation will implicitly call to_s, and is usually the easiest way to turn multiple objects into strings at once:

e = Helium.new
str = "Pi #{3.14} and element #{e}
# str is now "3.14 and element He"

Implicit conversion would allow you to make strings and numbers essentially equivalent. You could, for example, 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.

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.

  • + Share This
  • 🔖 Save To Your Account