Как включение модуля Ruby на самом деле не «множественное наследование» и как стиль Ruby позволяет избежать проблем, связанных с множественным наследованием? - PullRequest
13 голосов
/ 27 октября 2010

Матц предположительно сказал, что "миксины могут делать практически все, что делает множественное наследование, без связанных с этим недостатков" (слова Матца). "

Прежде всего, почему включение модуля Ruby не является «множественным наследованием»? Мне кажется, что между модулями и классами очень мало различий. Тот факт, что вы не можете создать экземпляр модуля, не имеет значения, когда он используется в качестве суперкласса.

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

Итак, что именно отличает миксины модулей Ruby от множественного наследования, скажем, в языке, подобном Python? И почему аргументы за принятие Python алгоритма c3 MRO не применимы к Ruby? И если они применимы - почему Ruby решил не применять этот алгоритм?

спасибо

Ответы [ 4 ]

4 голосов
/ 07 февраля 2011

С помощью MI многие возникающие проблемы можно урезать до деталей реализации;Вы не можете просто говорить о «множественном наследовании» вообще, не говоря об особенностях.Поэтому я предполагаю, что вы имеете в виду «множественное наследование C ++», когда говорите «множественное наследование».

Самая распространенная проблема с множественным наследованием - это Алмазная проблема .Если несколько суперклассов на одном уровне определяют один и тот же метод, как вы узнаете, какой метод вызывается в подклассе?

С модулями эта проблема легко решается - последний включенный модуль всегда "выигрывает".Вы не можете включать несколько модулей «одновременно», как вы можете делать с классами в C ++.Так что эта проблема никогда не возникает.

Тот факт, что вы не можете создать экземпляр модуля, не имеет значения, когда он используется в качестве суперкласса

С уважением, я не согласен.

Во-первых, модули никогда не «используются в качестве суперклассов» в ruby;только суперклассы.

Во-вторых, с множественным наследованием, точно знать, в каком порядке называются конструкторы (и деструкторы!), не является тривиальным вопросом .Тот факт, что ruby-модули не позволяют создавать экземпляры, полностью устраняет эту проблему.

3 голосов
/ 29 июня 2012

Добавление этого от имени Младена в качестве фактического ответа, потому что я нашел его очень полезным, и я предполагаю, что ответы лучше индексируются для любых сумасшедших вещей, которые С ним связаны.

ВотХорошая статья на этот счет, посмотрите, ответит ли она на ваш вопрос: http://artima.com/weblogs/viewpost.jsp?thread=246488 - Младен Ябланович 28 октября 2010 года в 18: 23

0 голосов
/ 16 ноября 2010

Наиболее важным в ruby ​​является перезапись предыдущих определений данных / функций каждым включенным модулем.

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

Таким образом, пример кода для написания нового модуля (логически):

old_function = fun
fun = define_new_function
  do_you_staff
  call old_function

Вам не нужно использовать старую функцию, хотя в большинстве случаев она полезна, но иногда проще переписать весьcode.

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

Этот метод также называется monkey patching -Термин широко используется в Ruby on Rails.

0 голосов
/ 27 октября 2010

Ознакомьтесь с книгой "Рубин метапрограммирования" от Pragmatic Press.В нем содержится очень подробное объяснение, которое очень легко читать и понимать.http://pragprog.com/titles/ppmetr/metaprogramming-ruby

Я не могу ответить на многие ваши вопросы, потому что я не знаю Python.но основа того, почему это не множественное наследование, заключается в том, что ruby ​​внедряет модуль в цепочку наследования, когда модуль включен или класс расширяется модулем.

class Foo
  include Bar
end

module Bar
end

foo = Foo.new

это создает цепочку наследования, где fooэкземпляр Foo и Foo наследуется от Bar.

это немного сложнее, чем просто, и существуют правила для порядка, в котором происходит внедрение наследования.книга, на которую я ссылался, очень хорошо объясняет это.

...