Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DelegateClass vs Class Inheritance in Ruby

Can someone please provide some insight as to when to use delegation via DelegateClass (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.

like image 334
Kyle Decot Avatar asked Aug 06 '16 21:08

Kyle Decot


People also ask

How many types of inheritance are there in Ruby?

Ruby supports only single class inheritance, it does not support multiple class inheritance but it supports mixins. The mixins are designed to implement multiple inheritances in Ruby, but it only inherits the interface part.

How do you inherit two classes in Ruby?

In Ruby, single class inheritance is supported, which means that one class can inherit from the other class, but it can't inherit from two super classes. In order to achieve multiple inheritance, Ruby provides something called mixins that one can make use of.

Why Multiple inheritance is not supported in Ruby?

Example# Multiple inheritance is a feature that allows one class to inherit from multiple classes(i.e., more than one parent). Ruby does not support multiple inheritance. It only supports single-inheritance (i.e. class can have only one parent), but you can use composition to build more complex classes using Modules.

Which operator is used to inherit the class in Ruby?

In Ruby, we use the < operator to create inheritance relations. The Human class inherits from the Being class. The super method calls the constructor of the parent class.


2 Answers

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

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.

like image 198
coreyward Avatar answered Sep 19 '22 16:09

coreyward


delegates model different behaviors of Person based on the context. e.g. the same person could be a seller in one context or a buyer in a different context. Inheritance is more rigid: a Bear and Tiger inherit from Animal, but an instance of Animal would never need to sometimes behave like a Bear and sometimes behave like a Tiger. An instance of a descendent of Animal is either one or the other.

like image 39
quinn Avatar answered Sep 16 '22 16:09

quinn