rubyguides

Kernel#String

String(object) → new_string

Signature

String(object) → new_string

String() takes exactly one argument. Calling it with zero arguments raises ArgumentError, as does calling it with two or more. Other Kernel converters such as Float(), Integer(), Complex(), and Rational() all accept an exception: keyword, but String() does not. To opt out of raising, rescue the resulting error or convert the value yourself first.

What it does

String is a module function on Kernel, mixed into every Object. You usually call it without a receiver, which makes it handy inside class bodies and DSLs, where you do not have a self to send a method to. The dispatch order is fixed:

  1. If the argument already responds to to_str, return its to_str result. This is the “I really am a string” branch and is trusted without rechecking the type.
  2. Otherwise, call to_s and return the result. Object#to_s is always defined, so this branch almost always succeeds.
  3. If neither method exists, raise TypeError: no implicit conversion of <Class> into String.

The result is a fresh, mutable String. The source object is not modified.

Examples

# Strings pass through
String("hello")
# => "hello"

# Numerics call to_s
String(42)
# => "42"
String(3.14)
# => "3.14"

# nil, true, and false have to_s defined on Object
String(nil)
# => ""
String(true)
# => "true"

# Collections use their inspect-style to_s
String([1, 2, 3])
# => "[1, 2, 3]"
String({ name: "Ada" })
# => "{:name=>\"Ada\"}"

# Symbol#to_s returns a frozen, cached String in MRI
String(:ok)
# => "ok"
String(:ok).frozen?
# => true

# A class that defines to_str wins over to_s
class Money
  def initialize(cents) = @cents = cents
  def to_str = "$#{@cents / 100}.#{'%02d' % (@cents % 100)}"
  def to_s    = "Money(#{@cents})"
end

String(Money.new(199))
# => "$1.99"

String() vs to_s vs String.new

You have three overlapping tools for “make a string out of this”:

  • obj.to_s is an instance method. It is always available, but a class can override it to return anything, including non-strings.
  • String(obj) is the Kernel function. It tries to_str first and falls back to to_s. A String always comes back.
  • String.new(obj) is the class constructor. It copies the argument and does not call to_s or to_str. String.new(42) raises TypeError, while String(42) returns "42".

Reach for String() when you have no receiver (in a DSL, for example), when you want to_str to win, or when you want a return-type guarantee that plain to_s does not give you.

# Same input, three different results
obj = 42

obj.to_s        # => "42"      (instance method; subclasses can override the return)
String(obj)     # => "42"      (Kernel function; honors to_str, then to_s)
String.new(obj) # TypeError: no implicit conversion of Integer into String

Gotchas

  • String(nil) returns "", not a TypeError. Compare to Integer(nil), which raises. This catches people who assume the Kernel converters are uniformly strict, and it is the most common surprise with this method.
  • The result is a new String, not the original. String("foo").equal?("foo") is false, so do not rely on object identity for caching or deduplication.
  • String() has strict arity. def to_str(x = "") = String(x) is the common workaround when you need a default.
  • With # frozen_string_literal: true, source literals are frozen, but String("foo") returns a mutable copy. That makes it a useful thaw idiom when you need to mutate a string you got from elsewhere.
  • String() does not change the encoding of its result. If you need a specific encoding, follow it up with String(arg).force_encoding("UTF-8").

See also

  • Kernel#Float — the sibling converter for floats, with its own exception: keyword.
  • Kernel#Integer — strict numeric conversion; raises where String() returns "".
  • Kernel#Array — the matching converter for turning objects into arrays.