Class#inherited: knowing which class inherits from another
Summary

In the previous page, we have seen the Module#included method, triggered when a module is included. The method inherited is instead called when a class inherits from another class.

The 2 methods can however be sometimes found in the same module; for example included can open the metaclass of the including class, and install an inherited method (mechanism used in Rails).

  1. A simple example to get started:
    class A
      
     def self.inherited(chld)
       puts "{chld} has inherited me(#{self})"
     end  
     
    end
    
    
    # classes B and C inherit
    
     class B < A; end
     class C < B; end
     
    # at startup, we would see:
    => B has inherited me (A)
    => C has inherited me (B)
    
    The example is simple but it shows something important: the propagation of the inherited trigger; although only class A has defined the it, all the classes inherit it (and it is as if they had defined it themselves); therefore, each time a class is subclassed, the inherited hits in that class (thus, it will happen once to each of B, C).
  2. It is important to contrast this with the behaviour of method included; we repeat the previous example, adding the inclusion of module M (which will define an included method) in A;

    class A                   
      include M 
      
     def self.inherited(chld)
       puts "{chld} has inherited me(#{self})"
     end                      
      
    end    
    
    module M                        
      def self.included(base) 
        puts "#{base} included #{self}"   
      end      
    end  
       
    class B < A; end             
    class C < B; end
    

    If we run this example, while inherited is invoked (as before) twice, included is instead invoked only once (for A). Although the methods of module M are available to all the classes (which, in an inheritance sense, are all including the module), included hits only for the class (A) explicitly doing the including.

    This must be kept in mind, also because both methods will often appear in the same module (as we will soon see), and it is useful to remember the distinction.

  3. Sometimes (eg, in Rails) the 2 methods are tucked in the same module. How can inherited end up in a module if, as we know, it must be declared in a class? the mechanism is ingenious: we can use included(base) which knows the class (=base) including the module, and thus it can open the class and define dynamically the inherited method on its behalf.

    In the following example we have a module which adds in a stack the classes in a hierarchy, using included to install the inherited method in the top class:

    module Stack
     @@stack = [ ]
      
     def self.included(base)
       @@stack << base
       
       base.class_eval do
         def self.inherited(child)
           @@stack << child
         end
         
         def self.show_stack; @@stack; end
       end 
     end  # included
     
    end # module
    
    
    class A
     include Stack
    end 
    
    class B < A
    end
    
    class C < B
    end
    
    class D < C
    end
    
    p A.show_stack  # => [A, B, C, D]
    
    
    Notice: a class variable (in this case, the array @@stack) is shared across the hierarchy, allowing the above algorithm to work.

    A small digression: in what we just wrote, you may have noticed that the terminology was a bit capricious: a class variable that is really scoped across the inheritance hierarchy? in fact, there is some rumbling in Ruby circles on whether this is a good idea, and class variables is an area that may change in Ruby (in my view, I do not think that there is anything sinful in having a type of variable that is shared across a hierarchy, if used wisely; the only sin was the name, class variable, not the concept. For more on the 3 types of class variables used in Rails, see this page).

    In any case, this was perfect to illustrate our simple example.

    A good familiarity with these mechanisms is fundamental to understand how Rails organizes modules and classes (in particular, the interaction between Controllers, Helper modules, and Views upon the arrival of a request; being described under the Rails section of the site).


[URL: ; Last updated: ]