Как наследование работает в Ruby?

По словам Дэйва Томаса в своем выступлении о объектной модели Ruby, в Ruby нет "методов классов". Существует только различие между тем, является ли получатель метода "объектом класса" или "объектом экземпляра".

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

По умолчанию, ancestors Метод не показывает метакласс:

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]

Тем не менее, я предполагаю, что реальный будет что-то вроде:

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

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

Теперь о наследстве.

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]

Следующее создаст новый собственный класс для B:

p B.metaclass.ancestors
# => [Class, Module, Object, Kernel, BasicObject]
p B.metaclass.instance_method(false)
# => []
  1. Как бы B.ancestors а также B.metaclass.ancestors выглядеть, когда собственные классы тоже включены? Метод say_hello хранится в собственном классе, (который я предполагаю B.class наследует) но где это?

  2. Так как есть две цепочки предков (B.ancestors а также B.class.ancestors или же B.metaclass.ancestors) как на самом деле происходит наследование?

3 ответа

Решение

Eigenclass является скрытым подлый. Вы успешно раскрыли это, открыв урок. Но его не существует у предков нормального класса. И поскольку он скрыт, вы не можете увидеть его, отправив ancestors метод самого собственного класса. Дерево наследования выглядит следующим образом:

B ---S-->  Dave   ---S---> Object  ---S---> BasicObject
|            |               |                  |
E            E               E                  E
|            |               |                  |
#B --S--> #Dave   ---S---> #Object ---S---> #BasicObject --S---> Class,,Object,BasicObject

S выступает за суперкласс, в то время как E для собственного класса.

Объект (а также класс, который является объектом, экземпляром класса) имеет поле класса, которое указывает на его класс. Создание одноэлементного класса (eigenclass/metaclass) создает анонимный класс и изменяет этот указатель так, чтобы он указывал на анонимный класс, указатель класса которого будет указывать на исходный класс. class Метод не отображает анонимный класс, только оригинальный класс. То же самое для миксинов. У класса есть поле суперкласса. Метод include создает анонимный прокси, указатель суперкласса изменяется для указания на анонимный прокси-класс, а оттуда на суперкласс. Метод ancestors не показывает анонимный класс, но имя включенного модуля. superclass Метод не отображает анонимный прокси-класс, только оригинальный суперкласс.

Вы можете прочитать это: почему символы в Ruby не считаются типом переменной?

В комментарии к этому ответу есть ссылка на интересную статью о синглтон-классе, которую можно найти в блоге Devalot.

Нужно некоторое время, чтобы ассимилировать эти цепочки наследования. Поскольку хорошая картина заслуживает длинного объяснения, я рекомендую главу 24 "Метапрограммирование в кирке" http://pragprog.com/book/ruby3/programming-ruby-1-9 которой есть различные картинки обо всех этих цепочках.

По умолчанию метод предков не показывает метакласс:
и 1. Как бы выглядели B.ancestors ..., когда также включены собственные классы?

ancestors касается цепочки суперкласса. Собственный класс не принадлежит цепочке суперкласса.

p Dave.metaclass.ancestors
=> [Класс, Модуль, Объект, Ядро, БазовыйОбъект]
Тем не менее, я предполагаю, что реальный будет что-то вроде:
=> ["собственный класс", класс, модуль, объект, ядро, базовый объект]

Правильный.

Вы можете упростить свой класс Дейва:

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 является лишним с Ruby 1.9.2, которая представила Object#singleton_class,

Другие вопросы по тегам