[ruby-core:94883] [Ruby master Bug#9603] unusual reference class-variable with cloned class.
From:
merch-redmine@...
Date:
2019-09-10 05:04:28 UTC
List:
ruby-core #94883
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: <mailto:ruby-core-request@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>