Ruby 模块包含为何不是真正的“多重继承”? Ruby 风格如何避免与多重继承相关的问题?
据推测,Matz 说“mixins 几乎可以完成多重继承所做的所有事情,而没有相关的缺点”(Matz 的话)。“
首先,为什么 Ruby 模块包含不是‘多重继承’?在我看来,模块之间几乎没有什么区别当模块用作超类时,无法实例化该模块这一事实是无关紧要的。
我也知道,连续的模块包含会形成从类向上延伸的单个继承链(而不是树)。足以将其与“多重继承”区分开来,因为 Python 多重继承系统还“线性化”超类链(使用 C3 算法)只是 Ruby 的“线性化”过程要简单得多。
那么,Ruby 模块混合与 Python 等语言中的多重继承到底有何区别呢? Python采用的c3 MRO算法适用于Ruby吗?如果它们确实适用,为什么 Ruby 决定不采用这种算法?
谢谢
Matz supposedly said "mixins could do almost everything multiple inheritance do, without the associated drawbacks" (Matz words)."
First of all, why is Ruby module inclusion not 'multiple inheritance' ? It seems to me there is very little difference between modules and classes. The fact you cannot instantiate a module is irrelevant when it is used as a superclass.
I also know that successive module inclusion forms a single inheritance chain (not tree) extending upwards from the class. But this, to me, is not sufficient to distinguish it from 'multiple inheritance' as the Python multiple inheritance system also "linearizes" the superclass chain (using the C3 algorithm) it's just that Ruby 'linearizing' process is significantly simpler.
So what exactly distinguishes Ruby module mixins from multiple inheritance in say a language like Python? And why don't the arguments behind the Python adoption of the c3 MRO algorithm apply to Ruby? And if they do apply - why did Ruby decide not to adopt this algorithm ?
thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
通过 MI,出现的许多问题都可以简化为实施细节;你不能只笼统地谈论“多重继承”,而不谈论具体细节。因此,当您说“多重继承”时,我假设您指的是“C++ 多重继承”。
多重继承最常见的问题是钻石问题。如果同一级别的多个超类定义了相同的方法,那么如何知道子类上调用了哪个方法?
使用模块,这个问题很容易得到解决——最后包含的模块总是“获胜”。您不能像使用 C++ 中的类那样“同时”包含多个模块。所以这个问题永远不会出现。
我谨表示不同意。
首先,模块在 ruby 中永远不会“用作超类”;只有超类是。
其次,对于多重继承,准确了解构造函数(和析构函数!)的调用顺序是 不是一件小事。 ruby 模块不允许实例化的事实完全抑制了这个问题。
With MI, lots of the issues that arise can be trimmed down to implementation details; you can't just talk about "Multiple inheritance" in general, without talking specifics. So I'll be assuming that you mean "C++ multiple inheritance" when you say "multiple inheritance".
The most common problem with Multiple inheritance is the Diamond Problem. If several superclasses on the same level define the same method, how do you know which method is invoked on the subclass?
With modules, this problem is easily answered - the last included module always "wins". You can't include several modules "simultaneously", as you can do with classes in C++. So this problem never arises.
I respectfully disagree.
First, modules are never "used as superclasses" in ruby; only superclasses are.
Second, with multiple inheritance, knowing exactly in what order the constructors (& destructors!) are called is not a trivial matter. The fact that ruby modules don't allow instantiation suppresses that problem altogether.
代表姆拉登将其添加为实际答案,因为我发现它非常有帮助,而且我猜答案对于使用它所做的任何疯狂的事情都会得到更好的索引。
Adding this on Mladen's behalf as an actual answer, because I found it very helpful, and I'm guessing answers get indexed better for whatever crazy things SO does with it.
查看 Pragmatic Press 的“Metaprogramming Ruby”一书。它以非常容易阅读和理解的方式对此进行了非常详细的解释。 http://pragprog.com/titles/ppmetr/metaprogramming-ruby
我不能回答你的大部分问题,因为我不懂Python。但它不是多重继承的基本原因是,当包含模块或模块扩展类时,Ruby 会将模块注入到继承链中。
这会产生一个继承链,其中 foo 是 Foo 的实例,而 Foo 继承自 Bar。
比这更棘手的是,继承注入发生的顺序是有规则的。我参考的书解释得很好。
Check out the book "Metaprogramming Ruby" from the Pragmatic Press. It contains a very detailed explanation of this, in a manner that is very easy to read and understand. http://pragprog.com/titles/ppmetr/metaprogramming-ruby
i can't answer mot of your questions because i don't know python. but the basics of why it's not multiple inheritance is that ruby injects the module into the inheritance chain when the module is included or a class is extended by a module.
this produces an inheritance chain where foo is an instance of Foo and Foo inherits from Bar.
it's a bit more tricky than just that, and there are rules for the order in which the inheritance injection occurs. the book i referenced explains it very well.
ruby 中最重要的是您可以使用每个包含的模块覆盖以前的数据/函数定义。
因此,这很糟糕,因为理论上每个新模块都应该负责访问以前被覆盖的代码。
因此,编写新模块的示例代码(逻辑上)是:
您不必使用旧函数,尽管在大多数情况下它很有用,但有时重写整个代码更容易。
每个包含的模块都会构建覆盖方法的链,因此多重继承不会有问题,但包含模块的顺序变得更加重要。
此方法也称为猴子修补 - Ruby on Rails 中广泛使用的术语。
Most important in ruby is you overwrite previous definitions of data/functions with every included module.
So it is bad as every new module should theoretical take care of giving access to previous code which gets overwritten.
So example code to write new module is (logically):
You do not have to use old function, although in most cases it's useful but sometimes it is easier to rewrite the whole code.
Each included module will build chain of overwritten methods, so there will be no problems with multiple inheritance but order of including modules gets more important.
This method is also called monkey patching - term widely used in Ruby on Rails.