my face
About Me

Published Posts

All Posts

New Post


View by Tag:

interviewing, code, testing, philosophy, blog, wantmyjob, virtualization, railsmud, heroku, ruby, published, neoarchaeology, railsgame, rails, juggernaut, astrino, cheaptoad, shannaspizza, mongodb, refactorit, devise, rvm, passenger


FeedBurner picture


Online Portfolio

Resume

Profile on LinkedIn

Recommend Me

Ruby Type Coercion

Posted: 2 years ago (2007-11-20 00:08:00 UTC ) / Updated: 15 months ago (2009-06-01 22:27:19 UTC )

Imported from WordPress

Originally posted on 2007-11-20 00:08:00

Ruby, like most languages, has various methods to turn one data type into another. Unlike other languages, it often uses that mechanism for type-checking.

Methods can do type-checking in at least two different ways. They can use the is_a? function to see whether the given object is of the right type, or they can try to turn it into an object of the right sort. Here's an example of the first method:

def myfunc(a_str, a_list)

raise "Not a string!" unless a_str.is_a?(String)
raise "Not a list!" unless a_list.is_a?(Array)

# now do what you actually want to
end


Pretty straightforward. This approach can work well. There are also various ways to automate it, as a subset of programming by contract or design by contract.

The second method takes about the same amount of code, though it's not always as clear what it's doing. It's probably also possible to automate, though I can't say I've seen a Ruby module to do so yet:

def myfunc(a_str, a_list)

a_str = a_str.to_str # no-op if a_str is already a string
a_list = a_str.to_ary # no-op if a_list is already an array

# now do what you actually want to
end


Unfortunately, Ruby doesn't seem to have an easy way to do the equivalent of CommonLISP's 'coerce' function. If you wrote one and called it lisp_coerce, then using it would look like this:
#This doesn't work because there's no such Ruby function as "lisp_coerce"

def myfunc(a_str, a_list)
a_str = a_str.lisp_coerce(String) # no-op if a_str is already a string
a_list = a_str.lisp_coerce(Array) # no-op if a_list is already a list

# now do what you actually want to
end


The idea is that it would return the object, interpreted as a different type. So 37 as a string would be "37", 37 as an array might be [37], and 37 as a hash table would raise an exception and tell you that you were being silly. Ruby actually does have a coerce method as part of its Numeric class. Unfortunately, Ruby's coerce takes two arguments, and attempts to get them into a compatible numeric representation. For instance, if you give it a Float and a Complex number, it will convert them both to Complex.

I say "unfortunately" because that means it can't be used as the lisp_coerce() statement above. Instead, you've got to find or guess the method names to turn one type into another, and many of them aren't all that obvious. This problem has been noticed, but there seems to be no real consensus on what the right answer looks like.

There is also another way to do it, though it's less consistently used: constructors. For instance:

# This doesn't work very well

def myfunc(a_str, a_list)
a_str = String.new(a_str)
a_list = Array.new(a_list)

#now do what you actually want to
end


Unfortunately, constructors often don't call the existing conversion functions. String.new, above, will die if given a FixNum, even though "37.to_str" works perfectly well. So this method isn't recommended for real use because the methods aren't in place.

So if you don't want your methods to just be stodgy and raise an exception on anything that isn't instantly similar, you'll need to use the methods to_int, to_str, to_hash and to_ary to convert to a FixNum, a String, a Hash and an Array, respectively. And you'll need to do some exploring if you want to convert to other classes, or define your own questionably-chosen names for your own classes. This is an area where Ruby could probably use some standards...

Previous: And then... / Next: Choosing What You Do

Edit | Destroy | See All Posts

blog comments powered by Disqus