Let It Quack!

Duck Crossing Warning SignAn entire day passed. The repugnant lines sat festering. Finally, their odious stench wafted strong enough to give me a start. What had I done?!

The situation started simply enough. I realized several kinds of transactions shared common logic. Despising duplication as a good programmer should, I placed this shared behavior in a base class which the various kinds of transactions would subclass.

I wanted to ensure that descendents of this parent class implemented a particular method. Declaring the method abstract would do this wonderfully—except Ruby doesn’t support abstract methods. What should I do? “Hum…the goal is to have an error raised if a particular method isn’t overridden. Ruby doesn’t use a compiler, so there’s no way to catch this at compile time. However, I can catch it at runtime—at least if the offending method is called. I know what I’ll do—I’ll define the method on the base class and have it raise an exception if called!”

Then, with the noblest of intentions, I innocently wrote this loathsome bit of code:

# the test
describe InventoryTransaction
       it ".type" do
               expect { subject.type }.to raise_error NotImplementedError
       end
end

# the implementation (my base class)
class InventoryTransaction
       # other code….
       def type
               raise NotImplementedError
       end
end

 

A day passed before the atrociousness of what I had done struck me.

My blunder? I tried to tell my duck what to do if someone mistreated it. Squawk loudly, I told it.

Ruby is duck-typed—if it walks like a duck and talks like a duck then the object can be treated like a duck. A mistreated duck knows how to squeal. Duck Crossing Warning Sign Up CloseIts built-in quack makes such a ruckus that it, barring immediate intervention, will crash the application. My well-intentioned code unnecessarily interfered with this already-sufficient behavior, impertinently introducing a vestige of static typing into Ruby’s duck-typed universe.

I repented, removed the offending superfluity and went back to happily coding away.

The moral of this lesson? In Ruby, if object wants to quack, get out of its way. Let it quack!

One thought on “Let It Quack!

  1. Dave Aronson

    Great post! As so often happens, it boils down to a requirements problem. You wrote: “the goal is to have an error raised if a particular method isn’t overridden.” Nope. The goal is to raise an error if a particular method isn’t *defined*, regardless of how it *would* have been defined (such as by overriding the definition from a base class). Had you realized that, then the answer (the same answer you got to eventually, NoMethodError) would have been obvious at that stage.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>