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?
Api::V3::PostDecorator.superclass
=> Api::V3::BaseDecorator
class Api::V3::PostDecorator < Api::V3::BaseDecorator; end
!! #<TypeError: superclass mismatch for class PostDecorator>
How is that a mismatch? The superclass is exactly what I am declaring as
I reopen the class.
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.
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.
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?
···
On Thu, Aug 29, 2013 at 11:33 AM, Leslie Viljoen <lists@ruby-forum.com>wrote:
#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
Kind regards
robert
···
On Thu, Aug 29, 2013 at 12:20 PM, Leslie Viljoen <lists@ruby-forum.com> 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.
On Thu, Aug 29, 2013 at 12:20 PM, Leslie Viljoen <lists@ruby-forum.com> > 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.
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.
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 `<main>'
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
···
On Thu, Aug 29, 2013 at 11:08 PM, Leslie Viljoen <lists@ruby-forum.com> wrote:
On Thu, Aug 29, 2013 at 12:20 PM, Leslie Viljoen <lists@ruby-forum.com> >> wrote: