Forum: Ruby can someone explain this?

Posted by Andy Bogdanov (evilbrain)
on 2011-03-13 21:10
# First I create a proc:
p = proc {
  self::X = Class.new
  def self.X
    X.new
  end
}

# Then I create a module:
A = Module.new(&p)
puts A.X # => #<A::X:0x9c2e774>

# Then i create another module:
B = Module.new(&p)
puts B.X # => #<B::X:0x9c39304>

# Everything seems to be ok.

# And now to the strange part.
# After module B was created A.X started to return instances of B::X
puts A.X # => #<B::X:0x9c38238>

If more modules are created with the same proc method X returns
instances of X from the last created module. If I use "self::X.new"
instead of "X.new" everything works as expected, but I can't understand
why it works like that with "X.new". Is this a bug or it's supposed to
be this way?
Posted by Ryan Davis (Guest)
on 2011-03-13 22:13
(Received via mailing list)
On Mar 13, 2011, at 13:10 , Andy Bogdanov wrote:

> puts A.X # => #<A::X:0x9c2e774>
>
> If more modules are created with the same proc method X returns
> instances of X from the last created module. If I use "self::X.new"
> instead of "X.new" everything works as expected, but I can't understand
> why it works like that with "X.new". Is this a bug or it's supposed to
> be this way?

I suggest you send that to ruby-core@
Posted by Michael Edgar (Guest)
on 2011-03-14 01:01
(Received via mailing list)
[+ruby-core]

Also note that calling A.module_eval(&p) after your code then changes 
both methods to create A instances.

In Ruby 1.9, there is an inline cache for constant references. Dumping 
the bytecode for the self.X method
shows this in action:

[3,
 [:trace, 8],
 4,
 [:trace, 1],
 [:getinlinecache, :label_11, 0],
 [:getconstant, :X],
 [:setinlinecache, 0],
 :label_11,
 [:send, :new, 0, nil, 0, 1],
 5,
 [:trace, 16],
 4,
 [:leave]]

If you use self::X.new in A/B.X, this forces constant resolution each 
time, and the inline cache is not used:

[3,
 [:trace, 8],
 4,
 [:trace, 1],
 [:putself],
 [:getconstant, :X],
 [:send, :new, 0, nil, 0, 1],
 5,
 [:trace, 16],
 4,
 [:leave]]

The proc is compiled only once, and thus so does the method definition. 
The two method objects
are in fact distinct, of course.

>> A.method(:X) == B.method(:X)
=> false

My best guess: the two methods likely share the same instruction 
sequence object, and thus the
same inline caches, and the cache is not properly clearing when it 
should be.

Michael Edgar
adgar@carboni.ca
http://carboni.ca/
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.