From: merch-redmine@... Date: 2019-09-10T05:04:28+00:00 Subject: [ruby-core:94883] [Ruby master Bug#9603] unusual reference class-variable with cloned class. Issue #9603 has been updated by jeremyevans0 (Jeremy Evans). Backport deleted (1.9.3: UNKNOWN, 2.0.0: UNKNOWN, 2.1: UNKNOWN) Status changed from Open to Rejected While not intuitive, I think this behavior is expected and not a bug. It is not relating to class cloning, it is due to class variable lookup. Normal class variable lookup (e.g. not using `Module#class_variable_{g,s}et`), uses crefs, making it more similar to constant lookup than method lookup. It skips crefs added by singleton classes as well as crefs added by *eval. See `vm_get_cvar_base` in `vm_inshelper.c` for the algorithm used to find the base class used for class variable lookup. Class variable lookup will look in the ancestors of the base class for the class variable. Taking the original post as an example. The first time `B.make_clone.make_instance` is called, it runs `@@value = 2`. At the point in that call, the active cref is `C` (not the clone of `C` created by `B.make_clone`). So at that point, it sets `@@value = 2` in `C`, not in the clone of `C`. When `data` is called on that it, that is a regular method and not a singleton method, so the class variable lookup uses the cloned class variable and not the original class variable in C. The second time `B.make_clone.make_instance` is run, the value for `@@value` has already been set to `2` in `C`, so there is no behavior change. Here's an example allowing you to see the difference: ```ruby class B def self.make_clone C.clone end class C @@value = 1 def self.make_instance @@value += 1 [data, new.data] end def self.data @@value end def data @@value end end end p B.make_clone.make_instance p B.make_clone.make_instance p B::C.make_instance p B.make_clone.make_instance ``` output is: ``` [2, 1] [3, 2] [4, 4] [5, 4] ``` To show this is not related to cloning, here's a similar example that does not use cloning: ```ruby class A @@value = 1 def foo @@value end end class B @@value = 2 def A.bar @@value = 3 end def foo @@value end end p A.new.foo p B.new.foo A.bar p A.new.foo p B.new.foo ``` The output for this program is: ``` 1 2 1 3 ``` Note how the call to `A.bar` set the `@@value` for `B`, not `A`. ---------------------------------------- Bug #9603: unusual reference class-variable with cloned class. https://bugs.ruby-lang.org/issues/9603#change-81498 * Author: Chiether (Norikaz Ishii) * Status: Rejected * Priority: Normal * Assignee: * Target version: * ruby -v: ruby 2.1.2p80 (2014-03-01 revision 45231) [x86_64-linux] * Backport: ---------------------------------------- description ----------- Maybe panic reference to class-variable in cloned class. Not really sure about bug. But hang over my head. I think minor irritant it which whether problem or not. because impractical code. sample code ----------- class A @@value = 1 def self.make_instance @@value = 2 new end def data @@value end end puts A.make_instance.data # => 2 -- collect!! class B def self.make_clone C.clone end class C @@value = 1 def self.make_instance @@value = 2 new end def data @@value end end end [pattern 1] puts B.make_clone.make_instance.data # => 1 -- wrong puts B.make_clone.make_instance.data # => 2 -- collect [pattern 2] puts B::C.make_instance.data # => 2 -- collect puts B.make_clone.make_instance.data # => 2 -- collect expected -------- [pattern 1] 2 2 [pattern 2] 2 2 actual ------ [pattern 1] 1 2 [pattern 2] 2 2 noticed ------- ruby-1.8.6-p420, ruby-1.9.3-p545, ruby 2.1.2p80 all problem. but codepad(1.8.6) is looking for expected. http://codepad.org/1VPpyCvy -- https://bugs.ruby-lang.org/ Unsubscribe: