Why a module's singleton method is not visible in downstream eigenclasses where it gets mixed?

前端 未结 2 708
渐次进展
渐次进展 2021-01-18 03:36

I understand the regular method lookup path i.e. class, superclass/module, all the way up to BasicObject. I thought it was true for singleton version of the cha

相关标签:
2条回答
  • 2021-01-18 04:23

    First of all, a class is an object, just like the other objects it also has its own superclass; second of all, Eigenclass itself is a normal class, only anonymous and sorta invisible; third, the eigenclass's superclass of the derived class is the eigenclass of the base class; Fourth, include includes instance methods (not singleton methods) of the included module, make them instance methods of the receiver class object.

    There're two parallel inheritance chains in your example

    Car < Vehicle < ...

    Car's eigenclass < Vehicle's eigenclass < Automobile < ...

    Do the following test on irb:

    class Object
      def eigenclass
        class << self
          self
        end
      end
    end
    
    Car.ancestors # => [Car, Vehicle, Object, Kernel, BasicObject]
    Car.eigenclass.ancestors # => [Automobile, Class, Module, Object, Kernel, BasicObject]
    Vehicle.eigenclass.ancestors # => [Automobile, Class, Module, Object, Kernel, BasicObject]
    Car.eigenclass.superclass.equal? Vehicle.eigenclass # => true
    

    You see, Automobile is in the eigenclass inheritance chain. But regretably, the ancestor method doesn't return invisible eigenclasses, nonetheless they are actually in the second chain.

    0 讨论(0)
  • 2021-01-18 04:26

    First of all, include does not include eigenclass methods as you might expect. Consider:

    module Foo
      class << self
        def do_something
          puts "Foo's eigenclass method does something"
        end
      end
    end
    
    module Bar
      include Foo
    end
    
    puts Bar.do_something
    # undefined method `do_something' for Bar:Module (NoMethodError)
    

    Note that this is consistent with the behavior of classically defined class methods:

    module Foo
      def self.do_something
        puts "Foo's class method does something"
      end
    end
    
    module Bar
      include Foo
    end
    
    puts Bar.do_something
    # undefined method `do_something' for Bar:Module (NoMethodError)
    

    A common idiom is to define the class methods in a submodule and then trigger a call to extend when the module is included:

    module Foo
      def self.included(base)
        base.extend ClassMethods
      end
    
      module ClassMethods
        def do_something
          puts "Foo::ClassMethod's instance method does something"
        end
      end
    end
    
    module Bar
      include Foo
    end
    
    puts Bar.do_something
    # Foo::ClassMethod's instance method does something
    

    The second thing to note is, that you are really including the instance methods of Automobile into the eigenclass of Vehicle, thus the instance methods of Automobile turn into (eigen)class methods of Vehicle.

    Your Car class basically has nothing to do with all this. The only thing to note here is, that class inheritance also makes class methods available, whereas include does not. Example:

    class Foo
      def self.do_something
        puts "Foo's class method does something"
      end
    end
    
    class Bar < Foo
    end
    
    puts Bar.do_something
    # "Foo's class method does something"
    
    0 讨论(0)
提交回复
热议问题