Glad You're Ready. Let's Get Started!

Let us know how we can contact you.

Thank you!

We'll respond shortly.

Second thoughts on initializing modules

This morning Yehuda Katz posted a response to my previous post, Technique for extending a method from a module, showing how a more modular organization of the Person class would allow for a solution that does not require a crazy meta programming hack. The idea is that by extracting the method we want to decorate into an ancestor class, Ruby makes it a lot easier to do what we want.

Previously I was aware that there were other ways I could structure the host class to make the module’s job easier but I did not try that because but I was writing the code with the knowledge that I would only be in control of one side of the equation, the module. The host class was going to be written by the end-user of the Rubygem the module was to be packaged in. Since I did not want to try dictate how the end-user structured the host class I ended up adding a lot of complexity to the module. The goal became how to write the module in a such a way that the class would “just work” upon including Teacher without requiring any additional steps to be taken. Asking the user to create an AbstractPerson class that contained their initialize method and then creating a subclass felt like an obtrusive request to make through a README that would ultimate negatively impact the user’s experience with the library.

Shortly after I put that blog post up I got this tweet from Josh Susser:

egad! are you sure you're solving the right problem?

I was trying to solve how to decorate the initialize method from a mixed-in module. My real problem however, was that I was trying to modify the behavior of the host’s initialize from a module which is a good way to get into trouble. I am now of the opinion that if the module does need to be instantiated in some way, a good solution is to provide a initialization style method that the host class can call.

class Person
  include Teacher

  def initialize
    # initialize person

An added benefit of this approach is that initialize_teacher can be called from anywhere, and doesn’t have to happen within This explicit instantiation violates my original goal of being unobtrusive to the user but it sidesteps the can of worms that the original approach has. One obvious problem that was likely to come up was the case where the module’s initialize needs to take a parameter. Once that happens it is not longer completely transparent to user. Even worse is if the host class’s initialize needs to take it’s own parameter. At that point it falls apart completely.

Credit to Austin Putman for suggesting this in a comment on the first post. Also thank you to Yehuda Katz for his informative post on writing modular ruby code.

  1. Maybe I’m missing the point, but why wouldn’t you just do this:

    module Teacher
      def initialize
        puts "initializing teacher"
    class Person
      include Teacher
      def initialize
        puts "initializing person"
    # initializing teacher
    # initializing person

    A simple call to super and you can get all the included modules to run initialize as well (presuming you call super in modules also).

  2. Hunter Gillane says:

    @John – Rob mentioned that the Teacher module was going to be packaged as a gem, so the person implementing the Person class would be someone using the gem. If they included another gem that defined an initialize method, there would be no guarantee that Teacher’s initialze method would be called, at least without making sure that all the included modules had a call to super, like you said. Even then, it seems like you might run into trouble dealing with all those super calls if the Teacher module’s initialze method took any parameters.

  3. Austin Putman says:

    Thanks for the hat tip, and happy Rubying!

  4. Rob Olson says:

    @John Nunemaker – Using `super` is a good solution. I would say it is not perfect because host class has to know to call `super`. In a real code base is not clear when reading the code what calling super is doing. There may be several modules being included and tracking the path the call to super is going to take can be nontrivial. Especially if the module lives in a library rubygem.

    I admit to regularly getting confused with where the module gets inserted in the lookup path. Thanks (and no thanks) to Java I instinctively associate calling `super` with inheritance and forget about going through mixins.

    @Hunter – The hypothetical situation of multiple module’s defining initialize shows how important it is for library/module authors to remember to call `super`.

Post a Comment

Your Information (Name required. Email address will not be displayed with comment.)

* Copy This Password *

* Type Or Paste Password Here *