Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.2k views
in Technique[技术] by (71.8m points)

oop - How does Inheritance work in Ruby?

According to Dave Thomas in his talk about the Ruby Object Model, there are no "class methods" in Ruby. There is only difference between whether the receiver of the method is a "class object" or an "instance object".

class Dave
  def InstaceMethod              ### will be stored in the current class (Dave)
    puts "Hi"
  end
  class << self                  ### Creates an eigenclass, if not created before
    def say_hello
      puts "Hello"
    end
  end
end

By default, ancestors method doesn't show the metaclass:

class Dave
  class << self
    def metaclass                ### A way to show the hidden eigenclass
      class << self; self; end
    end
  end
end

p Dave.ancestors
# => [Dave, Object, Kernel, BasicObject]
p Dave.metaclass.ancestors
# => [Class, Module, Object, Kernel, BasicObject]

However, I assume the real one would be something like:

# => [<eigenclass>, Class, Module, Object, Kernel, BasicObject]

p Dave.class.instance_method(false)
# => [:allocate, :new, :superclass]
p Dave.metaclass.instance_method(false)
# => [:say_hello, :metaclass]

Now the inheritence.

class B < Dave
end

p B.say_hello
# => "Hello"
p B.ancestors
# => [B, Dave, Object, Kernel, BasicObject]
p B.class.instance_methods(false)
# => [:allocate, :new, :superclass]

The following would create a new eigenclass for B:

p B.metaclass.ancestors
# => [Class, Module, Object, Kernel, BasicObject]
p B.metaclass.instance_method(false)
# => []
  1. How would the B.ancestors and B.metaclass.ancestors look like when the eigenclasses are also included? The method say_hello is stored in an eigenclass, (which I assume B.class inherits from) but where is that?

  2. Since there are two ancestor chains (B.ancestors and B.class.ancestors or B.metaclass.ancestors), how does the inheritance actually take place?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

An object (and also a class which is an object, instance of Class) has a class field which points to its class. Creating a singleton class (eigenclass/metaclass) creates an anonymous class and changes this pointer to point to the anonymous class, whose class pointer will point to the original class. The class method does not display the anonymous class, only the original class. The same for mixins. A class has a superclass field. The method include creates an anonymous proxy, the superclass pointer is changed to point to the anonymous proxy class, and from there to the superclass. The method ancestors does not show the anonymous class, but the name of the included module. The superclass method does not display the anonymous proxy class, only the original superclass.

You can read this : Why are symbols in Ruby not thought of as a type of variable?

In a comment to this answer, there is a link to an interesting article on singleton class that can be found on a Devalot blog.

One needs some time to assimilate these inheritance chains. As a good picture is worth a long explanation, I recommend chapter 24 Metaprogramming in The Pickaxe which has various pictures about all these chains.

By default, ancestors method doesn't show the metaclass:
and 1. How would the B.ancestors ... look like when the eigenclasses are also included?

ancestors concerns the superclass chain. The eigenclass does not belong to the superclass chain.

p Dave.metaclass.ancestors
=> [Class, Module, Object, Kernel, BasicObject]
However, I assume the real one would be something like:
=> ["eigenclass", Class, Module, Object, Kernel, BasicObject]

Correct.

You can simplify your Dave class :

class Dave
    def self.say_hello    # another way to create an eigenclass, if not created before
      puts "Hello"
    end
    def self.metaclass    # A way to show the hidden eigenclass
        class << self
            self
        end
    end
end

Dave.say_hello           # => Hello
Dave.new.class.say_hello # => Hello
p Dave.metaclass.instance_methods(false) # => [:say_hello, :metaclass]
p Dave.singleton_methods                 # => [:say_hello, :metaclass]

def self.metaclass is superfluous since Ruby 1.9.2, which has introduced Object#singleton_class.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...