Class Methods Considered Annoying

Challenge: given the following class, write a method #find_like_objects which will call the class method .find with attributes.

Simple enough:

OK, let’s add a requirement. The method #find_like_objects method must be in a module, which can be included in any class that defines .find.

That’s not a problem, we just need to make the method a bit more generic:

We should check that it still works even if .find is defined in a superclass:

Looks like all’s well. Are we done?

Well, if we want #find_like_objects to be truly generic, it should also work when .find is defined in a module. Does that work with the implementation above?

I guess not. What can we do to make it work? We could iterate through the list of ancestors to find the first one that responds to .find:

That’s it, right? Now we have a fully polymorphic #find_like_objects method that will work no matter where .find was defined, right? Well, yes, unless of course the .find method is defined in a singleton class…

Our nice generic #find_like_objects method ignored the singleton class and used the module version instead. What to do?

At last, we have an implementation of #.find_like_objects which will call the nearest-defined .find no matter where it lives. But it took eight lines of code to do it! The astute reader has probably already realized what we’ve done here: we’ve reimplemented Ruby’s polymorphic method searching rules manually. In a word, BLEAAARGH!

The lesson here? Don’t use class methods when you need polymorphic behavior. I would generalize that to say prefer instance methods to class methods where possible. In some languages, the rule is to use a class-level (or “static”) method for any method that doesn’t need access to instance variables, but in Ruby it’s usually better to define an instance method unless you absolutely need to call the method from the class level. You run into similar issues with class-level instance variables.