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?
--
Peter McLain
peter.mclain@gemstone.com
on 2010-03-03 20:03
on 2010-03-03 21:15
On 3/3/10, Peter McLain <peter.mclain@gemstone.com> wrote: > > Constant lookup behaves differently if there is a class versus a > module in the name: Extending your example a little to actually look up the constants instead of just checking if they're defined?: XYZ = 10 module M end class C end p defined? M::XYZ # => nil p defined? C::XYZ # => "constant" C::XYZ #(irb):13: warning: toplevel constant XYZ referenced by C::XYZ #=> 10 M::XYZ # raises NameError Note the warning for C::XYZ. You really shouldn't look up constants this way, so I think a little inconsistency like this is tolerable.
on 2010-03-03 22:57
On Mar 3, 2010, at 12:15 PM, Caleb Clausen wrote: > module M > #=> 10 > > M::XYZ > # raises NameError > > > Note the warning for C::XYZ. You really shouldn't look up constants > this way, so I think a little inconsistency like this is tolerable. Well, the code isn't mine, but I'd still like to understand if there is a rationale for the difference in behavior, or if this is just another MRI implementation detail that's leaked out. Currently, MagLev returns "constant" for both classes and modules, but that breaks third party code. E.g,: return unless defined? RDoc::VERSION # RDoc 1 does not have VERSION # code that blows up if RDoc 1 being used... One could argue that the proper test, which works for both classes and modules in all ruby implementations, is: return unless RDoc.const_defined? :VERSION But I'd still like to understand if the difference in behavior is intended or an implementation quirk, and if it is intended, what the rationale is. -- Peter McLain peter.mclain@gemstone.com
on 2010-03-03 23:46
On Wed, Mar 3, 2010 at 8:01 PM, Peter McLain <peter.mclain@gemstone.com> wrote: > > Â Â 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.
on 2010-03-03 23:51
On 3/3/10, Peter McLain <peter.mclain@gemstone.com> wrote: > modules in all ruby implementations, is: > > return unless RDoc.const_defined? :VERSION > > But I'd still like to understand if the difference in behavior is > intended or an implementation quirk, and if it is intended, what the > rationale is. Ok, I see your problem, and I sympathize. Collisions of the toplevel constant VERSION with VERSIONs defined inside classes are a repeated snafu. (It's bitten me.) This is probably why MRI 1.9 no longer defines VERSION, but RUBY_VERSION instead. I'd suspect this is unintended, but for an authoritative answer you'll have to get matz or another core maintainer to chime in. You might ask on ruby-core; I suspect those guys don't pay a lot of attention to this list nowadays.
on 2010-03-04 01:39
On Mar 3, 2010, at 2:45 PM, Xavier Noria 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 peter.mclain@gemstone.com
on 2010-03-04 02:08
On Thu, Mar 4, 2010 at 1:39 AM, Peter McLain <peter.mclain@gemstone.com> wrote: > 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. Yes I also checked the book and albeit it is clear that the algorithm applies to unqualified names, it is not that much clear what exactly applies to qualified names.
on 2010-03-07 11:35
On Thu, Mar 4, 2010 at 1:39 AM, Peter McLain <peter.mclain@gemstone.com> wrote: > Â (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. Or else the spec needs rewording. Looking for Object for non-scoped constants in modules seems like a lexical rule to me, akin to searching Module.nesting. In a scoped constant reference I wouldn't expect lexical-like steps to be followed, so it might be the case that M::XYZ does not have to look in Object, while C::XYZ needs to because of the ancestors rule. That would a posteriori explain MRI's behavior. We need an authoritative answer, I saw the question was posted to ruby-core, let's see.
on 2010-03-08 18:08
Since I didn't get a good answer here, I posted the question on ruby- core, and it looks like I've caught the attention of the core team. So, if you're interested in the resolution, you should follow: [ruby-core:28482] Question on scoped constant resolution Class vs Module On Mar 3, 2010, at 11:01 AM, Peter McLain wrote: > > p defined? M::XYZ # => nil > p defined? C::XYZ # => "constant" > > Is this difference intended? If so, what is the rationale? -- Peter McLain peter.mclain@gemstone.com
on 2010-03-12 23:49
On Sun, Mar 7, 2010 at 11:34 AM, Xavier Noria <fxn@hashref.com> wrote: > would a posteriori explain MRI's behavior. > > We need an authoritative answer, I saw the question was posted to > ruby-core, let's see. Just a followup, the spec has been indeed revised, M::X does not look in Object.
Please log in before posting. Registration is free and takes only a minute.
Existing account
(Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
Log in with Google account | Log in with Yahoo account
No account? Register here.