Problem
You have an object of one type and you want to use it as though it were of another type.
Solution
You might not have to do anything at all. Ruby doesn't enforce type safety unless the programmer has explicitly written it in. If your original class defines the same methods as the class you were thinking of converting it to, you might be able to use your object as is.
If you do have to convert from one class to another, Ruby provides conversion methods for most common paths:
"4".to_i # => 4 4.to_s # => "4" Time.now.to_f # => 1143572140.90932 { "key1" => "value1", "key2" => "value2" }.to_a # => [["key1", "value1"], ["key2", "value2"]]
If all else fails, you might be able to manually create an instance of the new class, and set its instance variables using the old data.
Discussion
Some programming languages have a "cast" operator that forces the compiler to treat an object of one type like an object of another type. A cast is usually a programmer's assertion that he knows more about the types of objects than the compiler. Ruby has no cast operator. From Ruby's perspective, type checking is just an extra hoop you have to jump through. A cast operator would make it easier to jump through that hoop, but Ruby omits the hoop altogether.
Wherever you're tempted to cast an object to another type, you should be able to just do nothing. If your object can be used as the other type, there's no problem: if not, then casting it to that type wouldn't have helped anyway.
Here's a concrete example. You probably don't need to convert a hash into an array just so you can pass it into an iteration method that expects an array. If that method only calls each on its argument, it doesn't really "expect an array:" it expects a reasonable implementation of each. Ruby hashes provide that implementation just as well as arrays.
def print_each(array) array.each { |x| puts x.inspect } end hash = { "pickled peppers" => "peck of", "sick sheep" => "sixth" } print_each(hash.to_a) # ["sick sheep", "sixth"] # ["pickled peppers", "peck of"] print_each(hash) # ["sick sheep", "sixth"] # ["pickled peppers", "peck of"]
Ruby does provide methods for converting one data type into another. These methods follow the naming convention to_[other type], and they usually create a brand new object of the new type, but containing the old data. They are generally used when you want to use some method of the new data type, or display or store the data in another format.
In the case of print_each, not converting the hash to an array gives the same results as converting, and the code is shorter and faster when it doesn't do the conversion. But converting a hash into an array of key-value pairs does let you call methods defined by Array but not by Hash. If what you really want is an arraysomething ordered, something you can modify with push and popthere's no reason not to convert to an array and stop using the hash.
array = hash.to_a # => [["sick sheep", "sixth"], ["pickled peppers", "peck of"]] # Print out a tongue-twisting invoice. until array.empty? item, quantity = array.pop puts "#{quantity} #{item}" end # peck of pickled peppers # sixth sick sheep
Some methods convert one data type to another as a side effect: for instance, sorting a hash implicitly converts it into an array, since hashes have no notion of ordering.
hash.sort # => [["pickled peppers", "peck of"], ["sick sheep", "sixth"]]
Number conversion and coercion
Most of the commonly used conversion methods in stock Ruby are in the number classes. This makes sense because arithmetic operations can give different results depending on the numeric types of the inputs. This is one place where Ruby's conversion methods are used as a substitute for casting. Here, to_f is used to force Ruby to perform floating-point division instead of integer division:
3/4 # => 0 3/4.to_f # => 0.75
Integers and floating-point numbers have to_i and to_f methods to convert back and forth between each other. BigDecimal or Rational objects define the same methods; they also define some brand new conversion methods: to_d to convert a number to BigDecimal, and to_r to convert a number to Rational. To convert to or from Rational objects you just have to require 'rational'. To convert to or from BigDecimal objects you must require 'bigdecimal' and also require 'bigdecimal/utils'.
require 'rational' Rational(1, 3).to_f # => 0.333333333333333 Rational(11, 5).to_i # => 2 2.to_r # => Rational(2, 1)
Here's a table that shows how to convert between Ruby's basic numeric types.
Integer |
Floating-point |
BigDecimal |
Rational |
|
---|---|---|---|---|
Integer |
to_i(identity) |
to_f |
to_r.to_d |
to_r |
Float |
to_i(decimal discard) |
to_f (new) |
to_d |
to_d.to_r (include bigdecimal/util) |
BigDecimal |
to_i |
to_f |
to_d (new) |
to_r (include bigdecimal/util) |
Rational |
to_i(dec discard) |
to_f (approx) |
to_d (include bigdecimal/util) |
to_r (identity) |
Two cases deserve special mention. You can't convert a floating-point number directly into rational number, but you can do it through BigDecimal. The result will be imprecise, because floating-point numbers are imprecise.
require 'bigdecimal' require 'bigdecimal/util' one_third = 1/3.0 # => 0.333333333333333 one_third.to_r # NoMethodError: undefined method 'to_r' for 0.333333333333333:Float one_third.to_d.to_r # => Rational(333333333333333, 1000000000000000)
Similarly, the best way to convert an Integer to a BigDecimal is to convert it to a rational number first.
20.to_d # NoMethodError: undefined method 'to_d' for 20:Fixnum 20.to_r.to_d # => #
When it needs to perform arithmetic operations on two numbers of different types, Ruby uses a method called coerce. Every numeric type implements a coerce method that takes a single number as its argument. It returns an array of two numbers: the object itself and the argument passed into coerce. Either or both numbers might undergo a conversion, but whatever happens, both the numbers in the return array must be of the same type. The arithmetic operation is performed on these two numbers, coerced into the same type.
This way, the authors of numeric classes don't have to make their arithmetic operations support operations on objects of different types. If they implement coerce, they know that their arithmetic operations will only be passed in another object of the same type.
This is easiest to see for the Complex class. Below, every input to coerce is transformed into an equivalent complex number so that it can be used in arithmetic operations along with the complex number i:
require 'complex' i = Complex(0, 1) # => Complex(0, 1) i.coerce(3) # => [Complex(3, 0), Complex(0, 1)] i.coerce(2.5) # => [Complex(2.5, 0), Complex(0, 1)]
This, incidentally, is why 3/4 uses integer division but 3/4.to_f uses floating-point division. 3.coerce(4) returns two integer objects, so the arithmetic methods of Fixnum are used. 3.coerce(4.0) returns two floating-point numbers, so the arithmetic methods of Float are used.
Other conversion methods
All Ruby objects define conversion methods to_s and inspect, which give a string representation of the object. Usually inspect is the more readable of the two formats.
[1, 2, 3].to_s # => "123" [1, 2, 3].inspect # => "[1, 2, 3]"
Here's a grab bag of other notable conversion methods found within the Ruby standard library. This should give you a picture of what Ruby conversion methods typically do.
See Also
Strings
Numbers
Date and Time
Arrays
Hashes
Files and Directories
Code Blocks and Iteration
Objects and Classes8
Modules and Namespaces
Reflection and Metaprogramming
XML and HTML
Graphics and Other File Formats
Databases and Persistence
Internet Services
Web Development Ruby on Rails
Web Services and Distributed Programming
Testing, Debugging, Optimizing, and Documenting
Packaging and Distributing Software
Automating Tasks with Rake
Multitasking and Multithreading
User Interface
Extending Ruby with Other Languages
System Administration