Thursday, August 28, 2008

Meta Can Be Readable

Stumbled upon this post today on why you should avoid meta programming. The author contends that meta programming in ruby can, one, slow down your code, and two, it can make you code too hard to follow.

If you read the article comments, you'll see that some responders have shown various ways of speeding up the code example he gave, so I'll leave that part alone. Instead let's focus on the readability issue. While you can definitely take things too far and over generalize a solution, there are some steps you can take to make the code easier to follow. Consider this refactoring:

module TimeMethods
  def self.define_time(sym, secs)
    module_eval <<-EOC, __FILE__, __LINE__
      def #{sym}; self * #{secs} end
      alias_method :#{sym}s, :#{sym}
    EOC
  end
  
  Numeric.send(:include, self)
  
  define_time :second, 1
  define_time :minute, 60.seconds
  define_time :hour,   60.minutes
  define_time :day,    24.hours
  define_time :week,   7.days
  define_time :year,   364.25.days
end

puts 2.years

All I did was move the tricky "magic" part into it's own method. Any class or module methods that we create will be available to us inside of that Class or Module definition. That makes the final part very where we use define_time very readable because it's declarative and intention revealing.

Don't be afraid of ruby meta programming. I think Giles Bowkett puts it perfectly when he says that it's not meta programming, it's just programming. We should use the same tools to refactor it as any other code.