Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

duplicatable module incorrect #6265

Closed
loz opened this Issue May 11, 2012 · 6 comments

Comments

Projects
None yet
7 participants
Contributor

loz commented May 11, 2012

http://api.rubyonrails.org/classes/Class.html#method-i-duplicable-3F

duplicable? for Class and Module is incorrect.

You can dup both, and get different objects, the example shown is misleading, as actually:

c = Class.new # => #Class:0x10328fd80
d = c.dup # => #Class:0x10328fd80
c == d #=> false

so d is actually a different object, even tho the .to_s showed something similar. You can def methods or modify d without effecting c. Perhaps this is just a ruby 1.9 thing, but it's not as specified now.

The same goes for module too.

I'm not sure whether Rails would go bang if we were duping classes because this was reporting the correct value. The only time I do it, is to modify a class in a test, to test class methods etc, and ensure I don't lose original implementation..

Owner

tenderlove commented May 17, 2012

Pink Warrior: THIS IS AN AWESOME TICKET! Yes, the documentation is incorrect (possibly the code too, I haven't checked). You can dup classes and modules.

Aaron: BUT WHY ARE THE INSPECTS THE SAME? THEY MUST BE THE SAME OBJECT!

Pink Warrior: Well, I'll tell you why

Class.inspect uses the default implementation of inspect, which turns around and calls to_s on itself. If we look up the implementation of to_s, we can see it's on Module:

irb(main):024:0> Class.method(:to_s)
=> #<Method: Class(Module)#to_s>
irb(main):025:0>

The MRI implementation of Module.to_s ends up calling the C function rb_class_name which in turn calls rb_class_path.

rb_class_path calculates the fully qualified name of the class. After calculation, it puts the calculated name on an internal cache on that class object. Ever other time the class name is needed, it simply pulls the name out of the cache.

Aaron: SO WHAT?????

Pink Warrior: Let me finish.

When the Class object is duped, the cache is not cleared. That means that calls to to_s on the new class object use the cached value. IRB automatically inspects the return value at each line, so as soon as we create the new class, the value is cached.

Aaron: MY ATTENTION SPAN IS WANING, SHOW ME SOME CODE

Pink Warrior: OK!

We can trick IRB through crafty uses of a semicolon:

irb(main):001:0> x = Class.new; y = x.dup; nil
=> nil
irb(main):002:0> [x, y]
=> [#<Class:0x007ffdb3b1f108>, #<Class:0x007ffdb3b1f0b8>]
irb(main):003:0> x.to_s == y.to_s
=> false
irb(main):004:0> 

You can see in this example that the inspects are now different!

Aaron: OMG I AM SO BORED GOODBYE.

Pink Warrior: See you soon!

Aaron: ❤️❤️❤️

Pink Warrior is so smart ❤️

Contributor

markmcspadden commented May 17, 2012

FWIW: object_id doesn't seem to be as big a liar as inspect (Also requires 100% less semicolons....but dang that's a cool trick.)

1.9.3p125 :001 > x = Class.new
 => #<Class:0x007fa329847550> 
1.9.3p125 :002 > y = x.dup
 => #<Class:0x007fa329847550> 
1.9.3p125 :003 > [x.object_id, y.object_id]
 => [70169376471720, 70169376480660] 
1.9.3p125 :004 > x.object_id == y.object_id
 => false

@josevalim josevalim closed this May 17, 2012

Contributor

dreamfall commented May 17, 2012

Awesome dialog <3

Contributor

loz commented May 17, 2012

It's funny because all I was wondering is if it really was wrong, and whether I should do a pull request to fix it, and then this happened!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment