`M.prepend M` has hidden side effect
M.prepend M raises ArgumentError, but it has hidden side effect.
module M; end class C; end C.prepend M C.include M M.prepend M rescue nil module M2; end M2.prepend M C.include M2 p C.ancestors # => [M, C, M2, M, M2, Object, Kernel, BasicObject]
module M; end class C; end C.prepend M C.include M module M2; end M2.prepend M C.include M2 p C.ancestors # => [M, C, M2, Object, Kernel, BasicObject]
Updated by jeremyevans0 (Jeremy Evans) over 1 year ago
There are two issues I noted here. One is that cyclic prepends modify the ancestor chain before raising an exception. A simple fix for that is to scan the module ancestor chain to look for a cyclic prepend before making a modification. I've submitted a pull request to fix that: https://github.com/ruby/ruby/pull/4165
That doesn't fix the issue in this example. The problem in this example is due to the optimization in 37e6c83609ac9d4c30ca4660ee16701e53cf82a3. I've tested reverting that commit and you get the expected result after doing so. However, that commit contains an important optimization. I don't see Alan Wu as an assignee on Redmine, so I'll commit on the related GitHub commit and see if he can look into it.
Updated by alanwu (Alan Wu) about 1 year ago
- Status changed from Open to Closed