This is in a Rails project, though this is more a generic Ruby question.
I have a “superclass mismatch” error in my project that I can’t explain.
Probably a class is being loaded twice, which is wrong but still should
not cause an error. Can anyone explain it?
The fact that they have the same name does not mean they are the same
object. A minimal example goes like this:
class C
end
class D < C
end
Object.send(:remove_const, :C)
class C
end
D.superclass # => "C"
C # => "C"
D.superclass.object_id # => 70208043796780
C.object_id # => 70208043796660
For some reason the classes in your code are different objects.
FWIW I tend to prefer class_eval for reopening because I don’t like to
repeat the superclass. Specifying the superclass belongs to the class
definition in my mind. But that is just a comment in passing, you need
to
figure out why are the object_ids different. I’d suspect some constant
not
being reloaded.
So the only way this can happen is if the constant is deleted and
recreated?
There are other scenarios like using an expression as superclass like a
Struct constructor for example, but with the code you showed that’s the
only reasonable assumption I can think of. A remove_const somewhere.
The way constant reloading works in Rails is that autoloaded constants
are
removed with remove_const, so when a new request arrives constant
autoloading is triggered on demand again. But note this is all about
constants, if you did X = C somewhere, and C was remove_const’ed, X
would
still hold the class object. It is an important distinction,
dependencies.rb technically deals with constants, it unloads and loads
constants, not classes or modules (though they are in practice as a
side-effect and works if you follow the golden path).
I’d need to know more about your application to be able to help further.
For example, which are the files where these constants are defined and
reopened?
I know which code causes the problem - it’s some manual loading that
should probably not be there. But you’ve helped me understand why the
error occurs so thanks a lot.
On Thu, Aug 29, 2013 at 12:20 PM, Leslie V. [email protected]
wrote:
I know which code causes the problem - it’s some manual loading that
should probably not be there. But you’ve helped me understand why the
error occurs so thanks a lot.
#remove_const is not needed - overwriting is sufficient
irb(main):001:0> class A;end
=> nil
irb(main):002:0> class B < A; end
=> nil
irb(main):003:0> B.superclass
=> A
irb(main):004:0> B.superclass.equal? A
=> true
irb(main):005:0> A = Class.new
(irb):5: warning: already initialized constant A
=> A
irb(main):006:0> B.superclass.equal? A
=> false
irb(main):007:0> B.superclass
=> A
irb(main):008:0> A
=> A
On Thu, Aug 29, 2013 at 12:20 PM, Leslie V. [email protected]
wrote:
I know which code causes the problem - it’s some manual loading that
should probably not be there. But you’ve helped me understand why the
error occurs so thanks a lot.
#remove_const is not needed - overwriting is sufficient
irb(main):001:0> class A;end
=> nil
irb(main):002:0> class B < A; end
=> nil
irb(main):003:0> B.superclass
=> A
irb(main):004:0> B.superclass.equal? A
=> true
irb(main):005:0> A = Class.new
(irb):5: warning: already initialized constant A
=> A
irb(main):006:0> B.superclass.equal? A
=> false
irb(main):007:0> B.superclass
=> A
irb(main):008:0> A
=> A
Yes but “Class.new” will always produce a class with a new object_id -
that’s not the same as reopening the class, which leaves the object_id
intact.
On Thu, Aug 29, 2013 at 11:08 PM, Leslie V. [email protected]
wrote:
=> nil
=> false
irb(main):007:0> B.superclass
=> A
irb(main):008:0> A
=> A
Yes but “Class.new” will always produce a class with a new object_id -
that’s not the same as reopening the class, which leaves the object_id
intact.
Yes, obviously. But what is your point? With reopening the class you
cannot produce the error you showed initially, can you?
irb(main):001:0> class A;end
=> nil
irb(main):002:0> class B < A; end
=> nil
irb(main):003:0> class B < A; def x; end end
=> nil
irb(main):004:0> class B; def y; end end
=> nil
irb(main):005:0> class A; def z; end end
=> nil
irb(main):006:0> class B < A; def a; end end
=> nil
irb(main):007:0> class B; def b; end end
=> nil
irb(main):008:0> A = Class.new
(irb):8: warning: already initialized constant A
=> A
irb(main):009:0> class B; def c; end end
=> nil
irb(main):010:0> class B < A; def e; end end
TypeError: superclass mismatch for class B
from (irb):10
from /usr/bin/irb:12:in `’
You said earlier:
So the only way this can happen is if the constant is deleted and
recreated? In my tests, modifying the class doesn’t change its ID.
And to that I replied that deleting the constant (i.e. #remove_const)
is not necessary (see quote at the beginning).
Kind regards
robert
This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.