Issue #17423 has been updated by jeremyevans0 (Jeremy Evans).


This stems from the change that `Module#prepend` (and `Module#include`) now affect classes already including the receiver.  You get the same behavior for Ruby 2.0-3.0 if you prepend M to A before including A in B:

```ruby
module M; end
module A; end
A.prepend M
class B; include A; end
B.prepend M
p B.ancestors
```

The difference for your original code is shown by B.ancestors before and after the prepend of M:

```ruby
module M; end
module A; end
class B; include A; end
A.send :prepend, M
p B.ancestors
B.send :prepend, M
p B.ancestors
```

Output:

```
$ ruby30 t1.rb
[B, M, A, Object, Kernel, BasicObject]
[B, M, A, Object, Kernel, BasicObject]
$ ruby27 t1.rb  
[B, A, Object, Kernel, BasicObject]
[M, B, A, Object, Kernel, BasicObject]
```

Ruby has never had `include` add a module to the ancestor chain if it already exists in the ancestor chain of the receiver, and has never had `prepend` add a module to the ancestor chain if it already exists in the ancestor chain before the superclass. Prior to Ruby 2.3, Ruby wouldn't prepend the module if it was anywhere in the ancestor chain.

I'm not opposed to allow `prepend` to ignore the existing ancestor chain and always prepend the module to it.  However, it seems to be a very risky change to make at the current time.  Maybe we can try after the release of 3.0?

----------------------------------------
Bug #17423: `Prepend` should prepend a module before the class
https://bugs.ruby-lang.org/issues/17423#change-89409

* Author: matz (Yukihiro Matsumoto)
* Status: Open
* Priority: Normal
* Assignee: jeremyevans0 (Jeremy Evans)
* Backport: 2.5: UNKNOWN, 2.6: UNKNOWN, 2.7: UNKNOWN
----------------------------------------
I see

```ruby
module M; end
module A; end
class B; include A; end

A.prepend M
B.prepend M
p B.ancestors
```

gives `[B, M, A, Object, Kernel, BasicObject]` now. It used to be `[M, B, A, Object, Kernel, BasicObject]`.

I think it should be prepended to class `B`. Probably it should be `[M, B, M, A, Object, Kernel, BasicObject]`.

The reason behind this change may be duplication removing, but considering the following code, it is OK to duplicate prepende modules.

```ruby
module M; end
class A; end
class B<A; end

A.prepend M
B.prepend M
p B.ancestors # => [M, B, M, A, Object, Kernel, BasicObject]
```

Am I missing something?

Matz.






-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>