
Duck Typing
Ruby is a dynamically typed language. Other languages are statically typed. The difference comes down to whether, and how, the language enforces the consistency of the type of variables. The consistency can be enforced (or not, as in Ruby) on the method arguments.
For example, a method can have a single argument, and there is nothing that restricts the code from calling that method and passing a variable of any data type. You can pass strings, arrays, and integers into any argument you want and Ruby will not complain. However, the method implementation may complain if you pass it a type that it cannot handle.
While this behavior leads to very flexible code, it can also lead to vulnerable code or code that needs to accommodate many different types. There is a split among developers, with some who prefer dynamically typed languages over statically typed languages.
As Ruby enthusiasts, we love dynamic typing because of its flexibility and expressiveness. In statically typed languages, you often have to declare the type ahead of time. However, you may not know or care about the type. If the variable passed into a method can be anything, then that would mean that we need to handle lots of different cases in code.
As long as the variable passed in behaves as you need it to, it doesn't matter what type is passed in. That is what is termed as duck typing.
For instance, say you implement a logging method that outputs the length of an object passed into it, as in the following example:
def log_items(myvar)
if myvar.kind_of?(Array) || myvar.kind_of?(Hash) || myvar.kind_of?(String)
puts "Logging item with length: #{myvar.length}"
end
end
In the preceding method, we are only logging items that respond to the length method. But what if there is a new type of object that also responds to length? Well, we would then have to add to the already quite long if conditional.
Instead, we can duck type the method so that it checks whether the variable responds to the method we need, in this case, length, as shown in the following code:
def log_items(myvar)
raise "Unhandled type" unless myvar.respond_to?(:length)
puts "Logging item with length: #{myvar.length}"
end
That is a lot cleaner and allows any object to be passed into the method and it will succeed as long as the object responds to the length method. respond_to? is a special Ruby method on all objects that allows code to check whether the method is defined or, rather, can respond_to the method in question, which is passed in as a symbol.
Duck typing gets its name from the old adage, "If it looks like a duck and it walks like a duck, then it is a duck." In other words, if an object has the characteristics that the method needs, we don't care about its type.