Subclassing Module For Fun and Profit

You think you’ve done everything with Ruby? How about subclassing Module? It’s an interesting technique that I’ve been experimenting with lately. One of the downsides of using modules in Ruby is that a module doesn’t have a state. When you mix it into another class you’re basically copying methods from one place to another. What if extending an object with new methods requires a state? Where would you put that state?

A good example is what every ORM out there does – adding attribute accessor methods. Let’s take a look how it’s usually done:

See that anonymous module? We define accessor methods in that module and then we include it into the Book class. The class has now both reader and writer defined and you are free to overwrite them and call super.

The downside of this approach is that we create an anonymous module that’s missing a state. If you inspect that module it won’t tell you anything useful apart from #Module:0x007f9e3b84f770>. The module doesn’t know what’s the name of the attribute it defines accessors for. That information can be important and it would be nice to encapsulate that knowledge in a single place.

It turns out it is possible to subclass Module to capture a state. Check out this example:

What did just happen?! So. Instead of an anonymous module, we create a module subclass and instantiate it passing the name of the attribute that we want to define accessors for. It’s no longer a dumb module with some methods. It’s a dynamic module instance that knows how it should define accessors on the classes that are extended by it. Sounds crazy. I know. But it works and it can allow to build methods dynamically in a much cleaner fashion than the “standard” anonymous modules approach.

So what do you think? Crazy? Dangerous? Or maybe just purely awesome and useful? Maybe you have used this technique too? I would love to learn about other use cases.

This technique has been brought to you by Emmanuel Gomez – thanks man for messing with our brains :)

  • Benedikt

    I like the idea. Have you thought about using the “included” callback instead of explicitly calling define_accessors?

    • http://solnic.eu/ solnic

      Ah of course I can! Thanks for reminding me this. I updated the example.

  • http://twitter.com/alex_paramonov Alexander Paramonov

    Some time ago i created a gem that do a similar work:
    https://github.com/AlexParamonov/inheritance_module_eval

  • rebo

    I like this technique, however there may be a slight error in your code. Running the above code will set the title accessors instance variable to @name. When I presume you want it as @title.

    You can fix this with @name_ivar = “@#{@name}”
    in #initialize
    then in the local scope before the define…
    name_ivar = @name_ivar
    and in the define_method blocks
    instance_variable_set(name_ivar, value)
    instance_variable_get(name_ivar)

    As appropriate.
    Messy but if you want the correct instance variable name this is one way, Im sure there is a better way but my brain isn’t working right now

    • http://solnic.eu/ solnic

      Thanks man. Nice catch :) I just fixed the example.

  • rebo

    Gist for my comment below:

    https://gist.github.com/3379625

  • Renato Zannon

    That’s some very cool metaprogramming!

    This post has motivated me to experiment a little, and I found that my using module_eval on the module instance, we don’t have to override “included”, and it works with “extend” transparently:https://gist.github.com/3616434

  • http://twitter.com/slawosz Sławosz

    Oh, I really like this solution!
    I have only one observation to your text – you write that methods are copied, but I think it would be better to write that including modules inplicity creates superclass that including class inherit from. And this super class has this module methods.

    Thanks for sharing this post!