Adding virtual methods to Ruby

Tuesday, February 28th, 2006

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!

Advertisements

4 Responses to “Adding virtual methods to Ruby”

  1. Max Bondaruk Says:

    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


  2. 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!

  3. Seungjin Says:

    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.


  4. 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!


Comments are closed.

%d bloggers like this: