Duck typing and I are in a fight.

A lot of rubyists like to extol the virtues of “duck typing”. That is, you determine the type of an object by the methods it responds to. If object.respond_to?(:quack), then it must be a Duck! This is bundled up with weak typing, where variables and method arguments are not required to be a specific type. I love weak typing (in most contexts I code in, anyway). Weak typing and I are not in a fight.

But I always prefer is_a? over responds_to?. Using responds_to?, you never know if

  • an object that does not responds_to? your method name now will in some future version, or even with some dynamic method definitions
  • an object that does responds_to? your method actually does anything reasonable or even safe when you call your method.

A counter-argument, according to Wikipedia, is that

the issue is handled by testing, and the necessary knowledge of the codebase required to maintain it

Bollocks.

Are you going to keep track of every public method of every third-party gem you are using? What about dynamically-defined methods? Sure, if you’re testing one of the core behaviors of your app you’ll be careful and will know what possible objects you might be dealing with. But somewhere in the corner of your app you’ve asked, almost as an aside, if something responds_to? :each, maybe because the input might be a Foo or an array of Foos. That’s all fine until the Bar gem that defined Foo decided it would be cool to allow you to enumerate an individual Foo, because under the hood a Foo is really a collection of Bazs. But you didn’t know that, and you shoudln’t have to.

You disagree. Really? Do you know all of the classes defined in Rails as well as you know your own code? Can you recite all of the Ruby Enumerable methods right now?

Instead, knowledge of your codebase allows you to master what names exist in what namespaces so that you know your constant Beatle refers to a musician and not a bug. This lets you use is_a? with reckless abandon: you know exactly what classes you’ve included into your app. While other gems are able to overwrite your namespaces, that would be rather rude of them. Not speaking very softly. Defining mew methods in their own classes, however, is not rude. You’re asking for trouble if in order to infer suitability you ask classes, in their own namespaces that you do not control, simply whether or not they have defined a method of an arbitrary name that could mean anything at all. You’re asking an object of an arbitray class that you think might be Array-like responds_to? :push, and you’re chugging along happily until someone calls your method with a NuclearLaunchButton object. Oops.