Search code examples
rubyinheritanceinitialization

Ruby - initialize inheritance, super with only certain arguments?


I've been playing around with Ruby as of late and I can't seem to find the answer to my question.

I have a class and a subclass. Class has some initialize method, and subclass has its own initialize method that is supposed to inherit some (but not all) variables from it and additionally add its own variables to the subclass objects.

My Person has @name, @age and @occupation.

My Viking is supposed to have a @name and @age which it inherits from Person, and additionally a @weapon which Person doesn't have. A Viking obviously doesn't need any @occupation, and shouldn't have one.

# doesn't work
class Person
  def initialize(name, age, occupation)
    @name = name
    @age = age
    @occupation = occupation
  end
end

class Viking < Person
  def initialize(name, age, weapon)
    super(name, age) # this seems to cause error
    @weapon = weapon
  end
end

eric = Viking.new("Eric", 24, 'broadsword') 
# ArgError: wrong number of arguments (2 for 3)

You can make it work in the following ways, but neither solution appeals to me

class Person
  def initialize(name, age, occupation = 'bug hunter')
    @name = name
    @age = age
    @occupation = occupation
  end
end

class Viking < Person
  def initialize(name, age, weapon)
    super(name, age)
    @weapon = weapon
  end
end

eric = Viking.new("Eric", 24, 'broadsword') 
# Eric now has an additional @occupation var from superclass initialize


class Person
  def initialize(name, age, occupation)
    @name = name
    @age = age
    @occupation = occupation
  end
end

class Viking < Person
  def initialize(name, age, occupation, weapon)
    super(name, age, occupation)
    @weapon = weapon
  end
end

eric = Viking.new("Eric", 24, 'pillager', 'broadsword')
# eric is now a pillager, but I don't want a Viking to have any @occupation

The question is either

  1. is it by design and I want to commit some Cardinal Sin against OOP principles?

  2. how do I get it to work the way I want to (preferably without any crazy complicated metaprogramming techniques etc)?


Solution

  • Yes, you are committing a Cardinal Sin (obviously, you are aware of it, since you are asking about it). :)

    You are breaking Liskov substitution principle (and probably some other named or unnamed rules).

    You should probably extract another class as a common superclass, which does not contain occupation. That will make everything much clearer and cleaner.