I think that will end up being part of the explanation, but I'm not yet convinced that it *should* be part of the explanation.
p M.ancestors # => [M]
p C.ancestors # => [C, Object, Kernel]
The explanation for constant lookup in the Flanagan/Matz book, Section 7.9, starts off:
"When a constant is referenced without any qualifying namespace..." and then goes on to explain constant lookup.
Under those rules, I would expect both M and C to find the constant, and indeed, using unqualified names, they both do find it:
XYZ = 10
module M
p XYZ # => 10
p defined? XYZ # => "constant"
end
class C
p XYZ # => 10
p defined? XYZ # => "constant"
end
But the original example was a fully qualified path: M::XYZ and C:XYZ. I didn't find any discussion of scoped constants. The draft ruby spec, however, leads me to believe that the MRI behavior is a bug.
Section 11.4.3.2 of the spec discusses Scoped constant references. Under my reading of that section, and our test case, then (following the logic in that section):
(a) the primary-expression is M,
(b) M is a module
(c 1) XYZ is the constant-identifier
(c 2) XYZ is not one of the constants defined in M
(c 3 i) There are no included modules in M (skip)
(c 3 ii) N/A
(c 3 iii) Goto step e of section 11.4.3.1
11.4.3.1
(e) M is not a class
(e 1) Search Object for a binding for XYZ
So we *should* find it in Object and MRI is incorrect to return nil.
Did I miss something?
···
On Mar 3, 2010, at 2:45 PM, Xavier Noria wrote:
On Wed, Mar 3, 2010 at 8:01 PM, Peter McLain <peter.mclain@gemstone.com > > wrote:
Constant lookup behaves differently if there is a class versus a
module in the name:
XYZ = 10
module M
end
class C
end
p defined? M::XYZ # => nil
p defined? C::XYZ # => "constant"
Is this difference intended? If so, what is the rationale?
I believe C::XYZ works because C is a subclass of Object.
-- Peter McLain
peter.mclain@gemstone.com