почему одноэлементные методы (AKA: методы класса) наследуются? - PullRequest
2 голосов
/ 04 мая 2019

Я немного удивлен таким поведением:

puts RUBY_VERSION # 2.4.1
class A
  class << A
    def my_method
      puts self
    end
  end
end

class B < A ; end

puts A.singleton_methods.inspect # [:my_method]
puts B.singleton_methods.inspect # [:my_method]
puts B.my_method # B
puts A.my_method # A

В метапрограммировании Ruby 2 (удивительная книга BTW) Паоло Перрота говорит:

Кроме того, у синглтон-классов естьтолько один экземпляр (отсюда их имя), и они не могут быть унаследованы

Но мы видим, что метод класса во фрагменте был унаследован B от A. Итак,Может кто-нибудь объяснить мне, как это работает?

Это такое поведение означает, что классы являются экземплярами одноэлементных классов?

(Я честно написал это, прежде чем перечитывать ту часть книги, в которой объясняется механизм наследования методов класса. Но теперь, когда японимаю это я до сих пор считаю интересной темой)

1 Ответ

2 голосов
/ 04 мая 2019

Почему методы класса наследуются?

  1. У каждого класса есть синглтон-класс,
  2. Когда есть иерархия наследования, цепочка наследования одноэлементных классов отражает «нормальные» предложения.
  3. В процессе поиска метода Ruby интерпретатор проходит через цепочку наследования классов-одиночек.
puts RUBY_VERSION # 2.4.1
class A
  class << A
    def my_method
      puts self
    end
  end
end

class B < A ; end

puts A.singleton_class == B.singleton_class.superclass # true
puts A == B.superclass # true

Таким образом, в процессе поиска метода интерпретатор переходит к одноэлементному классу B, ищет метод my_method не находит его там и переходит к классу синглтона A, и там он находит метод и выполнить его.

Но тогда мы должны признать, что, имея две цепочки наследования классов, они находятся в некотором роде в конкуренции, в том смысле, что одна из двух цепочек должна быть пройдена первой. Но какой ?, один из нормальных предложений или класс синглтонов?

Ну, если вы знаете лучше, пожалуйста, скажите мне, но код, кажется, говорит:

puts RUBY_VERSION # 2.4.1

class Class
  def my_method
    puts "Those who seek for gold dig up much earth and find a little."
  end
end

A = Class.new do
  class << self
    def my_method
      puts self
    end
  end
end

class B < A ; end

Class.new.my_method # Those who seek for gold dig up much earth and find a little.
A.my_method # A

Если бы «нормальная» цепочка наследования имела бы приоритет над цепочкой наследования одноэлементных классов, результат A.my_method был бы таким же, как и Class.new.my_method, поскольку класс A равен Class. Мы могли бы видеть это более ясно, если бы мы убрали метод синглтона A:

puts RUBY_VERSION # 2.4.1

class Class
  def my_method
    puts "Those who seek for gold dig up much earth and find a little."
  end
end

A = Class.new do
  # class << self
  #   def my_method
  #     puts self
  #   end
  # end
end

class B < A ; end

Class.new.my_method # Those who seek for gold dig up much earth and find a little.
A.my_method # Those who seek for gold dig up much earth and find a little.

Что это за поведение означает, что классы являются экземплярами одноэлементных классов?

Мне бы очень хотелось получить ответ на этот вопрос. Но я не уверен в этом. Не значит ли это, что, например, A является одновременно экземпляром Class и его собственным синглтон-классом? Двойное наследство!?

Если вы знаете лучше, поделитесь своими знаниями. Это очень интересная тема:)

...