August 30th, 2007
Method Aliasing and Aspect-Oriented Programming
One of the things that I have recently played with in Ruby is a sort of aspect-oriented programming. I say “sort of” because Ruby is not really an aspect-oriented language out of the box, but with some inconvenient constructs one can approach problems in this manner, using this mindset. I touched this because I am writing extensions to another program already written in this style. I think a lot of Rubyists do this when modularizing their code. What I saw was that one of the classes I needed to modify was modularized into several components:
class Shape module CurvySides # ... code supporting curvy sides here ... end module StraightSides # ... code supporting straight sides here ... end include CurvySides, StraightSides end
Actually, each concern was in a separate file:
require 'shape/curvy_sides' require 'shape/straight_sides' class Shape include CurvySides, StraightSides end
How is that for separation? But wait, you say… what if including each concern requires a change in behavior to the same method? You cannot just define the whole method in both modules; if you ran one the other would not get to assert its behavior.
The solution lies in Ruby’s method aliasing mechanism. Each module defines its own version of the method assuming that there is another, previously defined, version of the method to be called.
class Shape def side_length 0 end module CurvySides def self.included (base) base.send :alias_method, :side_length_without_curvy_sides, :side_length base.send :alias_method, :side_length, :side_length_with_curvy_sides end def side_length_with_curvy_sides side_length_without_curvy_sides + (... other computation ...) end end module StraightSides def self.included (base) base.send :alias_method, :side_length_without_straight_sides, :side_length base.send :alias_method, :side_length, :side_length_with_straight_sides end def side_length_with_straight_sides side_length_without_straight_sides + (... other computation ...) end end include CurvySides, StraightSides end
So it is not the prettiest code, but it effects the separation of programming concerns a la aspect-oriented programming. For version one of anything I write I will not be using this much, but I think that before someone publishes their work they should consider modularizing it in this way. In fact, this architecture has been a great help to me as I extend the functionality of the class myself. I am simply writing my modifications as modules that are included into the class just like its base functionality. Sometimes they augment existing methods, and I have to make the calls to #alias_method for the class, and sometimes I do not. In any case, it is fun!