From: merch-redmine@... Date: 2020-12-22T02:33:58+00:00 Subject: [ruby-core:101620] [Ruby master Bug#17423] `Prepend` should prepend a module before the class 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 [M, B, M, A, Object, Kernel, BasicObject] ``` Am I missing something? Matz. -- https://bugs.ruby-lang.org/ Unsubscribe: