On Mar 3, 2010, at 2:45 PM, Xavier N. wrote:
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.
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?
–
Peter McLain
[email protected]