22
FEB2006
Class Level Mix-ins
A question that comes up pretty often in Ruby circles was posed again today, by Xavier Noria:
#
# Is there standard idiom to add module methods to classes that mix them in?
#
# That is, I would like class C to croak:
#
module M
def self.croak
puts "Croak!"
end
end
class C
include M
croak # doesn't work
end
This brings up a couple of interesting points about mix-ins. Obviously, class methods are not easily added to things, but we generally want class methods so we can call them directly from the module. Here's how I deal with this issue.
First, instance methods are the way to go for anything you will be mixing in, period. With instance methods, you can inject them into a class or object. With anything else you have to start hacking. That gives us our first change:
module M
def croak
puts "Croak!"
end
end
Now, we really wanted a module method, so I've made things worse. However, as I've said, we have all the choices with this setup. Let's just mix the module into it's own class!
module M
extend self # creates self.croak
def croak
puts "Croak!"
end
end
This trick of duplicating all instance methods as module methods is quite handy. I use it in Rails to make testing helper methods trivial, for example. You basically get two interfaces for the price of one. You can call module methods or mix it into objects.
We've already seen how to fix Xavier's class using the new module, but here it is in writing:
class C
extend M
croak # works fine now
end
Remember, module methods are more powerful if they are instance methods, because you then have all the easy choices. Just mix them into whatever you like, even if it is the module itself.
Comments (1)
-
Gregory Brown March 3rd, 2006 Reply Link
Hmm... this now makes extend really clear to me, I've never hit a case where I absolutely needed it but plenty of places where this would have been handy if I knew how to use it.
Thanks James!