During a short conversation on the #ruby-lang IRC channel, someone asked whether Ruby supported C++ pure virtual methods. Out of the box, the answer is no. But the implementation is trivial:
class VirtualMethodCalledError < RuntimeError
attr :name
def initialize(name)
super("Virtual function '#{name}' called")
@name = name
end
end
class Module
def virtual(*methods)
methods.each do |m|
define_method(m) {
raise VirtualMethodCalledError, m
}
end
end
end
The usage is beautifully simple:
class VirtualThingy
virtual :doThingy
end
class ConcreteThingy < VirtualThingy
def doThingy
puts "Doin' my thing!"
end
end
begin
VirtualThingy.new.doThingy
rescue VirtualMethodCalledError => e
raise unless e.name == :doThingy
end
ConcreteThingy.new.doThingy
Please comment!

Tuesday, August 1st, 2006 at 7:59
class AllYourBase
def some_method
raise “Method must be overridden”
end
def some_other_method
raise “Method must be overridden”
end
end
class Derived < AllYourBase
def some_method
…
end
end
a = Derived.new
a.some_other_method # => Exception
Tuesday, August 1st, 2006 at 8:31
Max,
if you think about the DRY principle and look at your code, you should see a certain pattern that you have to repeat for every “virtual” method. This could become a burden if you had many virtual methods. The solution I offer above:
lets you write abstract classes really succinctly — less code means less bugs!
is easy to maintain since the behavior in case of invocation of a pure virtual method is defined in one place only rather than sprinkled throughout your system,
is easy to understand as the code carries more semantic.
Thanks for the feedback!
Sunday, December 23rd, 2007 at 8:31
The above way not only requires a dependency (the .virtual method), but means you can’t inherit from any other class. Furthermore it discourages duck-typing.
Tuesday, December 25th, 2007 at 10:41
You’re absolutely right!
I should have also highlighted that I have never ever used this pattern (or even thought of using it) in any production code, since it has no place in Ruby. This post was an attempt at showcasing Ruby’s flexibility.
Thanks for your comment!