Let's assume we have this Ruby class:
class MyClass
class << self
MC_CONST = 30
end
end
Then, let's instantiate MyClass
and add another constant to the object's metaclass:
m = MyClass.new
class << m
OBJ_MC_CONST = 50
end
There are no issues with the object singleton constant:
m.singleton_class::OBJ_MC_CONST # => 50 <-- [OK]
m.singleton_class.constants.include? :OBJ_MC_CONST # => true <- [OK]
But not exactly what I'd expect with the class singleton constant:
MyClass.singleton_class::MC_CONST # => 30 <-- [OK]
MyClass.singleton_class.const_get :MC_CONST # => 30 <-- [OK]
MyClass.singleton_class.constants.include? :MC_CONST # => false <-- [Why???]
Why on earth the array returned by .constants
method on metaclass of MyClass
class doesn't contain :MC_CONST? What am I missing here?
Thank you.
EDIT 1: This does appear to be a bug in MRI 2.x after all. I've filed a new issue with the Ruby core team: https://bugs.ruby-lang.org/issues/9413 to address this.
EDIT 2: This bug has apparently been fixed in https://bugs.ruby-lang.org/projects/ruby-trunk/repository/revisions/44628/diff/
I've explored a bit on this question and I think it is caused by a bug / inconsistency / idiosyncrasy of MRI.
On MRI 2.1.0, this code:
class MyClass
class << self
MC_CONST = 30
end
end
p MyClass.singleton_class.const_defined? :ABBA_CONST, false
p MyClass.singleton_class.const_defined? :MC_CONST, false
p MyClass.singleton_class.constants(false)
yields
false
true
[]
So the MC_CONST
constant is defined, but it is not available as a local constant of the class (I'm passing false to the various methods to disable the constant resolution and just keep it local to that class), which it should be indeed. If we check on the documentation of Module#constants it says:
Returns an array of the names of the constants accessible in mod. This includes the names of constants in any included modules (example at start of section), unless the all parameter is set to false.
Also see Module::const_defined?.
So it tells us to check const_defined?
to better understand the behaviour of constants
, but the two methods give different results!
Furthermore, on other Ruby implementation this code works as expected.
On JRuby 1.7.9, it yields:
false
true
[:MC_CONST]
On Rubinius 2.2.1, it yields:
false
true
[:MC_CONST]
Which is the expected behaviour :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With