Feature #1586
Including a module already present in ancestors should not be ignored
| Status: | Assigned | Start date: | 06/07/2009 | |
|---|---|---|---|---|
| Priority: | Normal | Due date: | ||
| Assignee: | % Done: | 0% |
||
| Category: | core | |||
| Target version: | 2.0.0 |
Description
The scenario: * I include Foo in Numeric to provide #bar * Some other library includes a module in Float to provide #bar * So I include Foo in Float to use my #bar * But including Foo in Float is ignored since it's already in the ancestor chain I think it should be added to the ancestor chain, even if it's already present, since I may want to override some other method earlier in the ancestor chain. # Including a module already included in a superclass is ignored >> module Foo; end => nil >> class Numeric; include Foo; end => Numeric >> Float.ancestors => [Float, Precision, Numeric, Foo, Comparable, Object, Kernel] >> class Float; include Foo; end => Float >> Float.ancestors => [Float, Precision, Numeric, Foo, Comparable, Object, Kernel] # Reversing the order of inclusion works as expected >> module Foo; end => nil >> class Float; include Foo; end => Float >> Float.ancestors => [Float, Foo, Precision, Numeric, Comparable, Object, Kernel] >> class Numeric; include Foo; end => Numeric >> Float.ancestors => [Float, Foo, Precision, Numeric, Foo, Comparable, Object, Kernel] # And so does including a dupe of the existing module in the subclass >> module Foo; end => nil >> class Numeric; include Foo; end => Numeric >> Float.ancestors => [Float, Precision, Numeric, Foo, Comparable, Object, Kernel] >> class Float; include Foo.dup; end => Float >> Float.ancestors => [Float, #<Module:0x19bcd40>, Precision, Numeric, Foo, Comparable, Object, Kernel]
History
Updated by nobu (Nobuyoshi Nakada) almost 3 years ago
- Category set to core
- Assignee set to matz (Yukihiro Matsumoto)
- Target version set to 3.0
Updated by RickDeNatale (Rick DeNatale) almost 3 years ago
Actually, for a while, back in 2006, Ruby 1.9 (in its experimental form) used to do just what this ticket asks for: http://talklikeaduck.denhaven2.com/2006/10/09/a-subtle-change-to-mixin-semantics-in-ruby-1-9 However, that change got reverted. I asked Matz why at RubyConf 2007, and documented our conversion http://talklikeaduck.denhaven2.com/2007/11/03/a-chat-with-matz-classs-variable-reversion-and-a-mystery-explained The problem is that MRI, and I guess YARV doesn't keep track of where in the chain of classes, and module proxies it found the currently executing method, so super is implemented by doing a method search starting with the klass of self, and proceding until the method is found a SECOND time. With this implementation it's easier to turn module re-inclusion into a nop than to deal with the consequences.
Updated by bitsweat (Jeremy Kemper) almost 3 years ago
Fascinating. Thanks for the history behind this, Rick. Despite the implementation difficulties, I'd like to see this choice revisited for a future Ruby. I consider it a bug.
Updated by shyouhei (Shyouhei Urabe) over 1 year ago
- Status changed from Open to Assigned
Updated by naruse (Yui NARUSE) 7 months ago
- Project changed from ruby-trunk to 14
- Category deleted (
core) - Target version deleted (
3.0)
Updated by naruse (Yui NARUSE) 7 months ago
- Project changed from 14 to ruby-trunk
Updated by mame (Yusuke Endoh) 3 months ago
- Status changed from Assigned to Rejected
I'm rejecting this feature ticket because no progress has been
made for a long time. See [ruby-core:42391].
This is indeed a hard issue.
There are two approaches to make it consistent:
A) prohibit multiple appearances of one module in ancestors
B) permit multiple appearances
I guess matz prefers A to B, so B will not be admissible. (just
my guess, though) The current behavior aims A, but is indeed
incomplete.
In casual use case, however, module inclusion is used statically,
i.e., used when a class is first defined.
Thus, no actual problem is caused in practical case, I think.
In addition, A will be very hard to implement completely. Even
if it is possible, I'm afraid that the behavior will be bug-prone
(for both user code and ruby impl), because it means that an
already-included module may be later removed from ancestors,
unexpectedly.
Thus, I think that we can not fix this elegantly and will not
change the current behavior. But we might have to do something
if there is any *concrete* scenario in that the current behavior
causes a trouble. Let us know such a scenario if you have.
--
Yusuke Endoh <mame@tsg.ne.jp>
Updated by ko1 (Koichi Sasada) 3 months ago
- Category set to core
- Status changed from Rejected to Open
- Target version set to 2.0.0
I want to change this behavior as permitting multiple modules in an ancestors list (option B).
Can I do it? (If I can, I'll implement it after this Apr).
Updated by marcandre (Marc-Andre Lafortune) 3 months ago
Koichi Sasada wrote:
> I want to change this behavior as permitting multiple modules in an ancestors list (option B).
>
> Can I do it? (If I can, I'll implement it after this Apr).
That would be great.
I'm assuming it be allowed to include a module multiple times in a row too?
module M
def to_s
"*" + super + "*"
end
end
3.times{ Fixnum.prepend(M) }
42.to_s # => "***42***"
Updated by shyouhei (Shyouhei Urabe) 2 months ago
- Status changed from Open to Assigned