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>