Tuesday, August 15, 2006

Removing kind_of? and is_a? from your code

The Object class of Ruby contains the identical methods is_a? and kind_of?. They take a single argument, a class, and returns true if class is the class of the object, or if class is one of the superclasses of the object or modules included in object. The kind_of? (or is_a?) method is generally used for determining behavior based on the type of class of a parameter.

Most often I've seen kind_of? appearing in methods that need different behavior depending on the class type of an argument. For example, in a SQL DSL I was recently working on we had a method that would surround string objects with quotes, but would simply call to_s on other objects such as instances of Symbol or Fixnum.
def columns(*args)
args.each |element|
if element.kind_of? String
@column_array << "'#{element}'"
else
@column_array << element.to_s
end
end
This code does solve the problem; however, I believe that the code is structured in response to the languages inability to overload methods and behave differently based on type.

An alternative solution is to take advantage of duck typing. If the method were rewritten to execute a method that any class could respond to, the if..else statement becomes unnecessary.
def columns(*args)
args.each |element|
@column_array << element.to_sql
end
end
Clearly, for this example to work each argument must respond to the to_sql method. Because Ruby's classes can be re-opened this change is trivial.
class String
def to_sql
"'#{self}'"
end
end

class Fixnum
def to_sql
self
end
end

class Symbol
def to_sql
self.to_s
end
end
An added benefit to duck typing is that you can pass any object that responds to to_sql. For example, if you wanted a class that would represent null in the database you could define a class that only responds to the to_sql method.
class DBNull
def to_sql
'null'
end
end
For more information on Duck Typing see the chapter in Programming Ruby.
Post a Comment