From: ko1@... Date: 2015-03-06T13:47:57+00:00 Subject: [ruby-core:68441] [Ruby trunk - Bug #10943] Singleton class expression (class << obj) should make be indivisual namespaces Issue #10943 has been updated by Koichi Sasada. Benoit Daloze wrote: > How will you implement Module.nesting then? > Attach a CREF to each method, which is only attached in the class< 1 def foo p CONST #=> 1 end end ``` Singleton class defintion should also introduce namespace for constant. ```ruby obj = Object.new class << obj CONST = 1 def foo CONST end end p obj.foo #=> 1 ``` No problem. Problem is sharing a singleton class definition with multiple objects. ```ruby objs = [] $i = 0 2.times{ objs << obj = Object.new class << obj CONST = ($i += 1) def foo CONST end end } p objs[0].foo p objs[1].foo ``` Please think about the answers (outputs). The above code makes two singleton classes independently. So that constant namespace should be made for each singleton classes. In fact, before Ruby 1.9.0, this program outputs "1\n2\n". Maybe your answer is same. However after Ruby 1.9.0, this program outputs "2\n2\n". This is a bug (not intentional behavior). JRuby and Rubinius also output not correct answers (interestingly JRuby prints "1\n1"). ``` $ ruby -v t.rb ruby 2.3.0dev (2015-01-27 trunk 49421) [x86_64-linux] 2 2 $ jruby-1.7.19/bin/jruby -v t.rb jruby 1.7.19 (1.9.3p551) 2015-01-29 20786bd on OpenJDK 64-Bit Server VM 1.7.0_75-b13 +jit [linux-amd64] 1 1 $ jruby-9.0.0.0.pre1/bin/jruby -v t.rb jruby 9.0.0.0.pre1 (2.2.0p0) 2015-01-20 d537cab OpenJDK 64-Bit Server VM 24.75-b04 on 1.7.0_75-b13 +jit [linux-amd64] 1 1 $ rbx-2.5.2/bin/rbx -v t.rb rubinius 2.5.2 (2.1.0 7a5b05b1 2015-01-30 3.4 JI) [x86_64-linux-gnu] 2 2 ``` I asked Matz and his answer is "This is a bug behavior". Moreover, on the independent namespace can make new classes/modules. ```ruby obj = Object.new class << obj class X # make end end ``` and it also has problem with multiple definitions. ```ruby objs = [] $xs = [] $i = 0 2.times{ objs << obj = Object.new class << obj CONST = ($i += 1) class X $xs << self CONST = ($i += 1) def foo CONST end end def x X end end } p $xs #=> [#::X, #::X] p objs[0].x #=> #::X <- should be #::X p objs[1].x #=> #::X p $xs[0].new.foo #=> 4 <- should be 2 p $xs[1].new.foo #=> 4 ``` This is a bug. (BTW, mruby works correctly!) # Reason of this behavior On MRI, the reason of this bug is wrong sharing a namespace with multiple namespaces. On MRI, the term "CREF" is a name of namespace data structure. Simply saying, I couldn't recognize such case, sharing a namespace by multiple namespaces. I was surprising that each singleton class expression make their own namespace. So that I store CREF data into each local ISeq (method bytecode). It means that each bytecode knows their own CREF. I had believed that one bytecode only has one namespace (CREF). But this assumption is not correct, as I described above. # Solution I decided to renew this feature. ISeq data should not have their own CREF, but method only should have. Push CREF onto each method frame (value stack, same location of SVAR). There is a (not small) patch and I will commit soon for Ruby 2.3. # Previous versions This is bug fix, but it changes Ruby semantics largely. I'm not sure how to treat it. Matz said that "we can not expect how affect this change for existing applications, so that no need for older versions". Please discuss about it. # Acknowledgement This bug was found during investigating [Bug #10871]. -- https://bugs.ruby-lang.org/