How do Ruby programmers do type checking? How do Ruby programmers do type checking? ruby ruby

How do Ruby programmers do type checking?


My personal way, which I am not sure if it a recommended way in general, is to type-check and do other validations once an error occurs. I put the type check routine in a rescue block. This way, I can avoid performance loss when correct arguments are given, but still give back the correct error message when an error occurs.

def foo arg1, arg2, arg3  ...  main_routine  ...rescue  ## check for type and other validations  raise "Expecting an array: #{arg1.inspect}" unless arg1.kind_of?(Array)  raise "The first argument must be of length 2: #{arg1.inspect}" unless arg1.length == 2  raise "Expecting a string: #{arg2.inspect}" unless arg2.kind_of?(String)  raise "The second argument must not be empty" if arg2.empty?  ...  raise "This is `foo''s bug. Something unexpected happened: #{$!.message}"end

Suppose in the main_routine, you use the method each on arg1 assuming that arg1 is an array. If it turns out that it is something else, to which each is not defined, then the bare error message will be something like method each not defined on ..., which, from the perspective of the user of the method foo, might be not helpful. In that case, the original error message will be replaced by the message Expecting an array: ..., which is much more helpful.


Ruby is, of course, dynamically typed.

Thus the method documentation determines the type contract; the type-information is moved from the formal type-system to the [informal type specification in the] method documentation. I mix generalities like "acts like an array" and specifics such as "is a string". The caller should only expect to work with the stated types.

If the caller violates this contract then anything can happen. The method need not worry: it was used incorrectly.

In light of the above, I avoid checking for a specific type and avoid trying to create overloads with such behavior.

Unit-tests can help ensure that the contract works for expected data.


If a method has a reason to exist, it will be called.

If reasonable tests are written, everything will be called.

And if every method is called, then every method will be type-checked.

Don't waste time putting in type checks that may unnecessarily constrain callers and will just duplicate the run-time check anyway. Spend that time writing tests instead.