Type Casting (type conversion) in Ruby
Let’s write a program to calculate your age in months. We’ll ask for the age in years, and our program will do calculation by multiplying this number by 12. Based on our knowledge from previous chapters we should have something like this:
puts "Your age?" age = gets age_months = age * 12 puts "Your age is " + age_months
What’s happening here? We defined
age_months variable, which represents the age in years multiplied by 12. It should work, but something is not right. Can you spot the mistake? Here is the result of running this program:
Your age? 30 Your age is 30 30 30 30 30 30 30 30 30 30 30 30
Uh-oh! There definitely must be some mistake. It turns out that we multiply String by a number (Integer). Try to run this program again and type
Your age? blabla Your age is blabla blabla blabla blabla blabla blabla blabla blabla blabla blabla blabla blabla
The type of
age variable is String. And when we multiply String by Integer, the result is the very long string (short string of “blabla” repeated 12 times). To fix this program we should multiply Integer by Integer. We already did it before, when had calculated the number of milliseconds in a day, everything was correct. This time we just need to convert (or “cast”) type String into Integer.
How we can do that? Quick documentation search for
gets function (or “method”, do you remember that words “function” and “method” are synonyms?) shows that this function returns results with a type of String. And it’s understandable, because
gets is “get string”. What we need now is “get integer” function. And if we believe in Ruby’s principle of a least surprise, it should be
geti, let’s check that:
$ irb geti NameError (undefined local variable or method `geti' for main:Object Did you mean? gets)
Oops! It didn’t work. But it was a nice try. There is no such method
geti, but something tells it will be implemented one day. Let’s think what else we can do to fix our program?
$ node > "123" * 1 123
Can we do the same trick in Ruby? Let’s try in REPL:
> "123" * 1 => "123" > ("123" * 1).class => String
No luck, it’s still String. But there should be other ways. Open up “String” class documentation to see the whole bunch of methods starting with
to. There is
to_i among these methods, which means “to Integer”, and it’s exactly what we need.
to_i is not something obvious, but in this case Ruby developers wanted to stay lean, and we have
to_i instead of
So, to convert a string into number we should use
> "123".to_i => 123 > "123".to_i.class => Integer
By the way, there is similar method with the name
to_s - “to string”, with this method you can convert Integer (and other types) into String.
Let’s try to rewrite our program to calculate age in months:
puts "Your age?" age = gets age_months = age.to_i * 12 puts "Your age is " + age_months
Run it one more time and… Error again!
app.rb:4:in `+': no implicit conversion of Integer into String (TypeError)
As you can see, Ruby shows that error is happening in file
app.rb on the line
4. Error says that we can’t sum up two different types: String and Integer. Let’s go ahead and fix it, using type casting for the second time:
puts "Your age?" age = gets age_months = age.to_i * 12 puts "Your age is " + age_months.to_s
Try to run:
$ ruby app.rb Your age? 30 Your age is 360
Finally it works! We did a great job and used type casting two times, on lines 3 and 4. There are some other ways to write this program, and often it’s just up to a programmer to decide which approach is better. For example, we can do type casting on line 2, without touching line 3 (still keeping type casting on line 4):
puts "Your age?" age = gets.to_i age_months = age * 12 puts "Your age is " + age_months.to_s
Or we can redefine variable
age by adding one more line:
puts "Your age?" age = gets age = age.to_i age_months = age * 12 puts "Your age is " + age_months.to_s
Or we can do the same trick, but without
age_months variable. Try do it yourself.