Project

General

Profile

Feature #21981

Updated by jhawthorn (John Hawthorn) 22 days ago

When a class or module is cloned, Ruby currently rewrites the CREF (constant reference) chain of each copied method so that it points at the new class instead of the original. I don't think this should happen, and methods on a cloned class should retain their original lexical scope. 

 This behaviour was introduced in Ruby 1.9 to fix [Bug #7107], which was reporting that a constant in the original class wasn't available. I think it was done this way because of Ruby's implementation at that time rather than a design choice. This had further changes and fixes in [Bug #10885], [Bug #15877] which were crashes or inconsistencies (stale cache). I'd like us to revisit the design of this behaviour so that it's more intuitive and consistent. 

 ``` ruby 
 class C 
   A = 1 
   def a; A; end 
 end 

 D = C.clone 
 D.const_set(:A, 2) 

 p C.new.a    # => 1 
 p D.new.a    # => 2, but I think it should be 1 
 ``` 

 In most all other cases in Ruby, methods keep their original lexical scope for constant references: inheritance, mixins, `define_method(..., klass.instance_method(...))`, etc. Cloning a class should behave the same. 

 I think cloning a class is fairly rare, and setting constants on the cloned class more so, but this could be a compatibility issue. This affects `@@class_variables` as well as `CONSTANTS`. FWIW, truffleruby doesn't seem to have this behaviour (which makes sense, part of why I want to remove it is that it's awkward for JIT compiling 😅). 

 https://github.com/ruby/ruby/pull/16651

Back