Kyle Decot Kyle Decot - 4 months ago 13
Ruby Question

DelegateClass vs Class Inheritance in Ruby

Can someone please provide some insight as to when to use delegation via

(e.g.
Seller < DelegateClass(Person)
) and when to use class inheritance (e.g.
Seller < Person
) in ruby?

class Seller < DelegateClass(Person)
def sales
...
end
end

class Seller < Person
def sales
...
end
end


When I was looking over the Ruby on Rails source on Github I found quite a few uses of
DelegateClass
.

Answer

There are a couple of differences that can help provide insight as to which approach to use.

The following examples build on this silly hypothetical:

1) You can safely delegate to primitives (e.g. String), but cannot always safely inherit from them

If you're building on top of Hash or String or Fixnum, you're safer using DelegateClass (or another delegator). For more on why, Steve Klabnik's cautioning is a good place to start).

2) DelegateClass makes it easy to “convert” a more general object into a more specific one

This makes it easier to accept an instance of a general object and make it behave in a way that's specific to your implementation:

class Message < DelegateClass(String);
  def print
    upcase
  end
end

# […]

def log(message)
  message = Message.new(message) unless message.is_a?(Message)
end

3) A gotcha: DelegateClass subclasses expect an instance of the delegated class as an argument to new

This can make it tricky to “subclass” classes that you're handing to library code. For example, this is a fairly common practice that won't work out of the box with DelegateClass:

class MyLogger < DelegateClass(ActiveSupport::Logger); end

Foo::ThirdParty::Library.configure do |c|
  c.logger = MyLogger # no good
end

This doesn't work because our library expects to behave like most loggers and instantiate without arguments. This can be addressed by defining initialize and creating an instance of ActiveSupport::Logger, but probably not the right solution in this case.

Cheers!