Overwriting – Sebastians Blog https://sgaul.de Neues aus den Softwareminen Mon, 30 Nov 2015 20:40:31 +0000 de-DE hourly 1 https://wordpress.org/?v=6.1.7 https://sgaul.de/wp-content/uploads/2019/02/cropped-sgaul-2-1-32x32.jpg Overwriting – Sebastians Blog https://sgaul.de 32 32 Overwriting and Overriding with define_method https://sgaul.de/2015/09/29/overriding-vs-overwriting/ Tue, 29 Sep 2015 15:06:38 +0000 https://sgaul.de/?p=2827 Overwriting and Overriding with define_method weiterlesen]]> Recently we stumbled upon this inheritance issue, which seemed very weird at the first:

class A
  def talk
    'A'
  end
end

class B < A
  def self.define_talk
    define_method :talk do
      super() << 'B'
    end
  end
end

class C < B
  define_talk
 
  def talk
    super << 'C'
  end
end

> C.new.talk
 => "AC"

The talk addition from class B doesn’t appear, even though define_talk is triggered by Class C. C’s super call seems to ignore its direct parent B.

Overriding vs Overwriting

The reason for that is the delayed execution of define_talk, which adds the talk method to C rather than B. The previous definition of C is equivalent to this:

class C < B
  # calling define_talk is equivalent to
  def talk
    super << 'B'
  end
 
  def talk
    super << 'C'
  end
end

The second definition of talk doesn’t override the first one, it overwrites it: The first definition is completely gone and therefore no longer available as super.

Overriding with Anonymous Modules

To fix this we need to ensure that B defines the method on B or another untouched inheritance layer. This layer can be an anonymous module created and included by the define_talk method:

class B < A
  def self.define_talk
    mod = Module.new do
      define_method :talk do
        super() << 'B'
      end
    end
    include mod
  end
end

Now C’s definition of talk only overrides the one of the anonymous module, which is therefore still available as super.

> C.new.talk
 => "ABC"
]]>