I always wondered why it is possible to reference top-level constants
through a module. For instance:
irb(main):001:0> class Foo; end
=> nil
irb(main):002:0> Foo::Array.eql?(Array)
(irb):2: warning: toplevel constant Array referenced by Foo::Array
=> true
If you ask me, I'd say the code above should fail with NameError.
What's the rationale for this behaviour?
It is a consequence of a couple of things.
First, formally, constants belong to modules. That's the way the language
works. When you say X = 1, that is defining a constant which cannot live in
the limbo, it needs to be tossed into some module. In the case of top-level
constants, by definition they go into Object.
Second, the algorithm for qualified constants performs a lookup in the
ancestor chain of the qualifying module.
So, as a side-effect of the general rules for constants, it turns out you
can access top-level constants that way, because Object is an ancestor of
all classes (who are not descendants of BasicObject without passing through
Object).
You can also write Object::Object::Object because of the same reason.
···
On Fri, Sep 11, 2015 at 8:50 AM, Greg Navis <contact@gregnavis.com> wrote:
I can see how the two rules Xavier described lead to the aforementioned
behaviour. What I find puzzling, though, is the warning. Wouldn't it be
more useful if the interpreter raised a NameError instead of issuing a
warning, would it? Or is there a use for the warning that I'm not aware of?
PS The whole process is clearly described in Conrad Irwin's article [1]
It's a great read for any Rubyist.
On Fri, Sep 11, 2015 at 7:03 PM, Xavier Noria <fxn@hashref.com> wrote:
On Fri, Sep 11, 2015 at 8:50 AM, Greg Navis <contact@gregnavis.com> wrote:
Hi,
I always wondered why it is possible to reference top-level constants
through a module. For instance:
irb(main):001:0> class Foo; end
=> nil
irb(main):002:0> Foo::Array.eql?(Array)
(irb):2: warning: toplevel constant Array referenced by Foo::Array
=> true
If you ask me, I'd say the code above should fail with NameError.
What's the rationale for this behaviour?
It is a consequence of a couple of things.
First, formally, constants belong to modules. That's the way the language
works. When you say X = 1, that is defining a constant which cannot live in
the limbo, it needs to be tossed into some module. In the case of top-level
constants, by definition they go into Object.
Second, the algorithm for qualified constants performs a lookup in the
ancestor chain of the qualifying module.
So, as a side-effect of the general rules for constants, it turns out you
can access top-level constants that way, because Object is an ancestor of
all classes (who are not descendants of BasicObject without passing through
Object).
You can also write Object::Object::Object because of the same reason.
Shouldn't ruby VM create a global scope and put all constants including
Array, Object Into that scope. As ruby is known for not surprising user, I
think it would have been more appropriate.
···
On 11 Sep 2015 22:35, "Xavier Noria" <fxn@hashref.com> wrote:
On Fri, Sep 11, 2015 at 8:50 AM, Greg Navis <contact@gregnavis.com> wrote:
Hi,
I always wondered why it is possible to reference top-level constants
through a module. For instance:
irb(main):001:0> class Foo; end
=> nil
irb(main):002:0> Foo::Array.eql?(Array)
(irb):2: warning: toplevel constant Array referenced by Foo::Array
=> true
If you ask me, I'd say the code above should fail with NameError.
What's the rationale for this behaviour?
It is a consequence of a couple of things.
First, formally, constants belong to modules. That's the way the language
works. When you say X = 1, that is defining a constant which cannot live in
the limbo, it needs to be tossed into some module. In the case of top-level
constants, by definition they go into Object.
Second, the algorithm for qualified constants performs a lookup in the
ancestor chain of the qualifying module.
So, as a side-effect of the general rules for constants, it turns out you
can access top-level constants that way, because Object is an ancestor of
all classes (who are not descendants of BasicObject without passing through
Object).
You can also write Object::Object::Object because of the same reason.
Also now I cannot Define Constants in Object without making then global.
$ irb
class Object
ABC = 23
end
=> 23
ABC
=> 23
:\ A little disappointment I think.
···
On Sat, Sep 12, 2015 at 12:10 AM, Arun kant sharma <iarunkant@gmail.com> wrote:
Shouldn't ruby VM create a global scope and put all constants including
Array, Object Into that scope. As ruby is known for not surprising user, I
think it would have been more appropriate.
On 11 Sep 2015 22:35, "Xavier Noria" <fxn@hashref.com> wrote:
On Fri, Sep 11, 2015 at 8:50 AM, Greg Navis <contact@gregnavis.com> >> wrote:
Hi,
I always wondered why it is possible to reference top-level constants
through a module. For instance:
irb(main):001:0> class Foo; end
=> nil
irb(main):002:0> Foo::Array.eql?(Array)
(irb):2: warning: toplevel constant Array referenced by Foo::Array
=> true
If you ask me, I'd say the code above should fail with NameError.
What's the rationale for this behaviour?
It is a consequence of a couple of things.
First, formally, constants belong to modules. That's the way the language
works. When you say X = 1, that is defining a constant which cannot live in
the limbo, it needs to be tossed into some module. In the case of top-level
constants, by definition they go into Object.
Second, the algorithm for qualified constants performs a lookup in the
ancestor chain of the qualifying module.
So, as a side-effect of the general rules for constants, it turns out you
can access top-level constants that way, because Object is an ancestor of
all classes (who are not descendants of BasicObject without passing through
Object).
You can also write Object::Object::Object because of the same reason.
I think the warning is a nicety of Ruby that handles this special
case. Anything else (like changing inheritance rules or introducing a
global scope independent from Object) would probably make things more
complicated - especially in light of the fact of the vast amount of
code that was written and tested against the current rules and would
have to be retested for subtle issues.
Cheers
robert
···
On Fri, Sep 11, 2015 at 11:45 PM, Greg Navis <contact@gregnavis.com> wrote:
I can see how the two rules Xavier described lead to the aforementioned
behaviour. What I find puzzling, though, is the warning. Wouldn't it be more
useful if the interpreter raised a NameError instead of issuing a warning,
would it? Or is there a use for the warning that I'm not aware of?
Robert, I don't want to change such fundamental rules. I mentioned raising
an raising a NameError. That would look more reasonable (at least on the
surface). The interpreter is clearly aware that ::Foo::Array references
::Array. In order to follow the principle of least surprise, it could raise
a NameError instead of emitting a warning. I'm just wondering what's the
rationale behind the current behaviour.
Best regards
Greg Navis
···
On Sat, Sep 12, 2015 at 12:35 PM, Robert Klemme <shortcutter@googlemail.com> wrote:
On Fri, Sep 11, 2015 at 11:45 PM, Greg Navis <contact@gregnavis.com> > wrote:
> I can see how the two rules Xavier described lead to the aforementioned
> behaviour. What I find puzzling, though, is the warning. Wouldn't it be
more
> useful if the interpreter raised a NameError instead of issuing a
warning,
> would it? Or is there a use for the warning that I'm not aware of?
I think the warning is a nicety of Ruby that handles this special
case. Anything else (like changing inheritance rules or introducing a
global scope independent from Object) would probably make things more
complicated - especially in light of the fact of the vast amount of
code that was written and tested against the current rules and would
have to be retested for subtle issues.
Robert, I don't want to change such fundamental rules.
You do want because:
I mentioned raising an raising a NameError.
Now the resolution would not work and you would have changed name
resolution rules by adding an exception for constants defined in
Object's scope.
That would look more reasonable (at least on the
surface). The interpreter is clearly aware that ::Foo::Array references
::Array. In order to follow the principle of least surprise, it could raise
a NameError instead of emitting a warning. I'm just wondering what's the
rationale behind the current behaviour.
If Matz reads this he might give you an answer.
Kind regards
robert
···
On Sat, Sep 12, 2015 at 3:33 PM, Greg Navis <contact@gregnavis.com> wrote:
You're right, Robert. I silently assumed no one relies on this behaviour. Murphy's Law guarantees that someone does depend on it.
My question was more hypothetical in nature: what's the design rationale
for the warning? If we had to restart Ruby from scratch wouldn't it be
better to raise a NameError?
···
On Sat, Sep 12, 2015 at 8:08 PM, Robert Klemme <shortcutter@googlemail.com> wrote:
On Sat, Sep 12, 2015 at 3:33 PM, Greg Navis <contact@gregnavis.com> wrote:
> Robert, I don't want to change such fundamental rules.
You do want because:
> I mentioned raising an raising a NameError.
Now the resolution would not work and you would have changed name
resolution rules by adding an exception for constants defined in
Object's scope.
> That would look more reasonable (at least on the
> surface). The interpreter is clearly aware that ::Foo::Array references
> ::Array. In order to follow the principle of least surprise, it could
raise
> a NameError instead of emitting a warning. I'm just wondering what's the
> rationale behind the current behaviour.
You're right, Robert. I silently assumed no one relies on this behaviour. Murphy's Law guarantees that someone does depend on it.
My question was more hypothetical in nature: what's the design rationale for
the warning? If we had to restart Ruby from scratch wouldn't it be better to
raise a NameError?
I haven't fully thought through this. Since I am not Matz I cannot
tell you his design rationale. But since he did a lot of great
decisions in designing Ruby I tend to trust him that there is a solid
reason for that design.
One reason might be that it keeps language semantics simpler and helps
treating Object as an ordinary type. The warning is just an additional
nicety to help you detect errors because it is very probably that you
did a mistake when referencing something from Object's scope via any
other class or module scope.
Kind regards
robert
···
On Mon, Sep 14, 2015 at 5:32 PM, Greg Navis <contact@gregnavis.com> wrote: