constants defined in Kernel are also defined in Object?

Discussion in 'Ruby' started by Paul Brannan, Feb 28, 2008.

  1. Paul Brannan

    Paul Brannan Guest

    This seems peculiar to me:

    cout@bean:~/tmp$ ruby -e 'module M; FOO = 42; end; class Foo; include M; end; p Foo.const_defined?:)FOO)'
    false
    cout@bean:~/tmp$ ruby -e 'Kernel.const_set:)FOO, 42); p Object.const_defined?:)FOO)'
    true
    cout@bean:~/tmp$ ruby -e 'Kernel.const_set:)FOO, 42); p Class.const_defined?:)FOO)'
    false

    Is there a reason for this behavior?

    Paul
     
    Paul Brannan, Feb 28, 2008
    #1
    1. Advertising

  2. On Fri, Feb 29, 2008 at 02:17:33AM +0900, Paul Brannan wrote:
    > This seems peculiar to me:
    >
    > cout@bean:~/tmp$ ruby -e 'module M; FOO = 42; end; class Foo; include M; end; p Foo.const_defined?:)FOO)'
    > false
    > cout@bean:~/tmp$ ruby -e 'Kernel.const_set:)FOO, 42); p Object.const_defined?:)FOO)'
    > true
    > cout@bean:~/tmp$ ruby -e 'Kernel.const_set:)FOO, 42); p Class.const_defined?:)FOO)'
    > false
    >
    > Is there a reason for this behavior?


    % ruby -e 'p Object.ancestors'
    [Object, Kernel]
    %

    Kernel is included by Object.

    > Paul

    --Greg
     
    Gregory Seidman, Feb 28, 2008
    #2
    1. Advertising

  3. Gregory Seidman wrote:
    > On Fri, Feb 29, 2008 at 02:17:33AM +0900, Paul Brannan wrote:
    >> This seems peculiar to me:
    >>
    >> cout@bean:~/tmp$ ruby -e 'module M; FOO = 42; end; class Foo; include M; end; p Foo.const_defined?:)FOO)'
    >> false
    >> cout@bean:~/tmp$ ruby -e 'Kernel.const_set:)FOO, 42); p Object.const_defined?:)FOO)'
    >> true
    >> cout@bean:~/tmp$ ruby -e 'Kernel.const_set:)FOO, 42); p Class.const_defined?:)FOO)'
    >> false
    >>
    >> Is there a reason for this behavior?

    >
    > % ruby -e 'p Object.ancestors'
    > [Object, Kernel]
    > %
    >
    > Kernel is included by Object.


    And M is included by Foo, yet the analogy breaks down in the outputs of

    Object.const_defined?:)FOO)

    Foo.const_defined?:)FOO)

    --
    vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407
     
    Joel VanderWerf, Feb 28, 2008
    #3
  4. On Fri, Feb 29, 2008 at 06:08:38AM +0900, Joel VanderWerf wrote:
    > Gregory Seidman wrote:
    >> On Fri, Feb 29, 2008 at 02:17:33AM +0900, Paul Brannan wrote:
    >>> This seems peculiar to me:
    >>>
    >>> cout@bean:~/tmp$ ruby -e 'module M; FOO = 42; end; class Foo; include M; end; p Foo.const_defined?:)FOO)'
    >>> false
    >>> cout@bean:~/tmp$ ruby -e 'Kernel.const_set:)FOO, 42); p Object.const_defined?:)FOO)'
    >>> true
    >>> cout@bean:~/tmp$ ruby -e 'Kernel.const_set:)FOO, 42); p Class.const_defined?:)FOO)'
    >>> false
    >>>
    >>> Is there a reason for this behavior?

    >>
    >> % ruby -e 'p Object.ancestors'
    >> [Object, Kernel]
    >> %
    >>
    >> Kernel is included by Object.

    >
    > And M is included by Foo, yet the analogy breaks down in the outputs of
    >
    > Object.const_defined?:)FOO)
    >
    > Foo.const_defined?:)FOO)


    Hunh. I didn't read closely. A little playing in irb reveals the same
    thing. That's odd. I have no answer for you.

    > vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

    --Greg
     
    Gregory Seidman, Feb 28, 2008
    #4
  5. Paul Brannan

    Jeremy Evans Guest

    Paul Brannan wrote:
    > This seems peculiar to me:
    >
    > cout@bean:~/tmp$ ruby -e 'module M; FOO = 42; end; class Foo; include M;
    > end; p Foo.const_defined?:)FOO)'
    > false
    > cout@bean:~/tmp$ ruby -e 'Kernel.const_set:)FOO, 42); p
    > Object.const_defined?:)FOO)'
    > true
    > cout@bean:~/tmp$ ruby -e 'Kernel.const_set:)FOO, 42); p
    > Class.const_defined?:)FOO)'
    > false
    >
    > Is there a reason for this behavior?


    Yes. Namespaces:

    irb(main):001:0> module M
    irb(main):002:1> FOO = 42
    irb(main):003:1> end
    => 42
    irb(main):004:0> class Foo
    irb(main):005:1> include M
    irb(main):006:1> end
    => Foo
    irb(main):007:0> Foo.const_defined?:)FOO) # looks for Foo:FOO
    => false
    irb(main):008:0> Foo::M.const_defined?:)FOO) # looks for Foo::M::FOO
    (irb):8: warning: toplevel constant M referenced by Foo::M
    => true
    irb(main):009:0> Object.const_defined?:)FOO) # looks for FOO
    => false
    irb(main):010:0> Kernel.const_set:)FOO, 42) # sets FOO
    => 42
    irb(main):011:0> Object.const_defined?:)FOO) # looks for FOO
    => true
    irb(main):012:0> Class.const_defined?:)FOO) # looks for Class::FOO
    => false
    irb(main):013:0> Class.const_set:)FOO, 42) # sets Class::FOO
    => 42
    irb(main):014:0> Class.const_defined?:)FOO) # looks for Class::FOO
    => true

    Jeremy
    --
    Posted via http://www.ruby-forum.com/.
     
    Jeremy Evans, Feb 28, 2008
    #5
  6. Paul Brannan

    Arlen Cuss Guest

    Hi,

    How about this?

    > And M is included by Foo, yet the analogy breaks down in the outputs of
    >
    > Object.const_defined?:)FOO)
    >
    > Foo.const_defined?:)FOO)


    >> Kernel.const_set:)FOO, 42)

    => 42
    >> Class::FOO

    => 42
    >> class Foo; end

    => nil
    >> Foo::FOO

    => 42
    >>


    Arlen
     
    Arlen Cuss, Feb 28, 2008
    #6
  7. Jeremy Evans wrote:
    > Paul Brannan wrote:
    >> This seems peculiar to me:
    >>
    >> cout@bean:~/tmp$ ruby -e 'module M; FOO = 42; end; class Foo; include M;
    >> end; p Foo.const_defined?:)FOO)'
    >> false
    >> cout@bean:~/tmp$ ruby -e 'Kernel.const_set:)FOO, 42); p
    >> Object.const_defined?:)FOO)'
    >> true
    >> cout@bean:~/tmp$ ruby -e 'Kernel.const_set:)FOO, 42); p
    >> Class.const_defined?:)FOO)'
    >> false
    >>
    >> Is there a reason for this behavior?

    >
    > Yes. Namespaces:
    >
    > irb(main):001:0> module M
    > irb(main):002:1> FOO = 42
    > irb(main):003:1> end
    > => 42
    > irb(main):004:0> class Foo
    > irb(main):005:1> include M
    > irb(main):006:1> end
    > => Foo
    > irb(main):007:0> Foo.const_defined?:)FOO) # looks for Foo:FOO
    > => false
    > irb(main):008:0> Foo::M.const_defined?:)FOO) # looks for Foo::M::FOO
    > (irb):8: warning: toplevel constant M referenced by Foo::M
    > => true
    > irb(main):009:0> Object.const_defined?:)FOO) # looks for FOO
    > => false
    > irb(main):010:0> Kernel.const_set:)FOO, 42) # sets FOO
    > => 42
    > irb(main):011:0> Object.const_defined?:)FOO) # looks for FOO
    > => true
    > irb(main):012:0> Class.const_defined?:)FOO) # looks for Class::FOO
    > => false
    > irb(main):013:0> Class.const_set:)FOO, 42) # sets Class::FOO
    > => 42
    > irb(main):014:0> Class.const_defined?:)FOO) # looks for Class::FOO
    > => true


    There still seems to be something unique in the relationship between
    Kernel and Object. Can you replicate it?


    module MyKernel
    FOO = 42
    end

    module Kernel
    FOO = 42
    end

    class MyObject
    include MyKernel
    extend MyKernel
    # what else do we have to do?
    end

    # Alternatives to assigning to FOO above
    MyKernel.const_set:)BAR, 42)
    Kernel.const_set:)BAR, 42)

    p MyObject.const_defined?:)FOO) # ==> false
    p MyObject.const_defined?:)BAR) # ==> false

    p Object.const_defined?:)FOO) # ==> true
    p Object.const_defined?:)BAR) # ==> true


    Can you make the outputs be true in the MyObject case?

    The following works for constants that are already defined _only_ (which
    is _not_ how Object and Kernel behave):

    class MyObject
    MyKernel.constants.each do |c|
    const_set(c, MyKernel.const_get(c))
    end
    end

    --
    vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407
     
    Joel VanderWerf, Feb 28, 2008
    #7
  8. Arlen Cuss wrote:
    > Hi,
    >
    > How about this?
    >
    >> And M is included by Foo, yet the analogy breaks down in the outputs of
    >>
    >> Object.const_defined?:)FOO)
    >>
    >> Foo.const_defined?:)FOO)

    >
    >>> Kernel.const_set:)FOO, 42)

    > => 42
    >>> Class::FOO

    > => 42
    >>> class Foo; end

    > => nil
    >>> Foo::FOO

    > => 42


    But:

    Kernel.const_set:)FOO, 42)
    class Foo; end
    p Foo::FOO # ==> 42
    p Foo.const_defined?:)FOO) # ==> false
    p Object.const_defined?:)FOO) # ==> true

    --
    vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407
     
    Joel VanderWerf, Feb 28, 2008
    #8
  9. Paul Brannan

    Arlen Cuss Guest

    On Fri, Feb 29, 2008 at 10:30 AM, Joel VanderWerf
    <> wrote:
    > But:
    >
    >
    > Kernel.const_set:)FOO, 42)
    > class Foo; end
    > p Foo::FOO # ==> 42
    >
    > p Foo.const_defined?:)FOO) # ==> false
    >
    > p Object.const_defined?:)FOO) # ==> true


    Indeed! It works in both cases because Foo is an Object, Object
    includes Kernel -- Foo won't tell you that FOO is defined because Foo
    didn't define it itself!

    I've been writing a new parser and byte-code VM for Ruby recently
    (http://rubyex.sairyx.org/, excuse the advertising), which meant
    figuring out the whole Ruby object model. This had me tricked at
    several stages, but here's how I summarised it to myself:

    1. Foo is an instance of Object [eventually].
    2. Object mixes in Kernel.
    2.a. Kernel's constants are Object's too.
    3. Foo::SOME_CONST will see through to Object::SOME_CONST and then
    that to Kernel::SOME_CONST.

    Correct me if I'm wrong in some detail.

    Arlen
     
    Arlen Cuss, Feb 28, 2008
    #9
  10. Paul Brannan

    Jeremy Evans Guest

    Joel VanderWerf wrote:
    > Jeremy Evans wrote:
    >>> Class.const_defined?:)FOO)'

    >> irb(main):004:0> class Foo
    >> irb(main):010:0> Kernel.const_set:)FOO, 42) # sets FOO
    >> => 42
    >> irb(main):011:0> Object.const_defined?:)FOO) # looks for FOO
    >> => true
    >> irb(main):012:0> Class.const_defined?:)FOO) # looks for Class::FOO
    >> => false
    >> irb(main):013:0> Class.const_set:)FOO, 42) # sets Class::FOO
    >> => 42
    >> irb(main):014:0> Class.const_defined?:)FOO) # looks for Class::FOO
    >> => true

    >
    > There still seems to be something unique in the relationship between
    > Kernel and Object. Can you replicate it?


    I think that Kernel and Object are special in that their constants are
    available in the top level namespace. Other than there isn't much
    difference between them and other classes in this case.

    > module MyKernel
    > FOO = 42
    > end
    >
    > module Kernel
    > FOO = 42
    > end
    >
    > class MyObject
    > include MyKernel
    > extend MyKernel
    > # what else do we have to do?
    > end
    >
    > # Alternatives to assigning to FOO above
    > MyKernel.const_set:)BAR, 42)
    > Kernel.const_set:)BAR, 42)
    >
    > p MyObject.const_defined?:)FOO) # ==> false
    > p MyObject.const_defined?:)BAR) # ==> false
    >
    > p Object.const_defined?:)FOO) # ==> true
    > p Object.const_defined?:)BAR) # ==> true
    >
    >
    > Can you make the outputs be true in the MyObject case?


    irb(main):001:0> module MyKernel
    irb(main):002:1> def self.included(klass)
    irb(main):003:2> klass.const_set:)FOO, 42)
    irb(main):004:2> end
    irb(main):005:1> end
    => nil
    irb(main):006:0> class MyObject
    irb(main):007:1> include MyKernel
    irb(main):008:1> end
    => MyObject
    irb(main):009:0> MyObject.const_defined?:)FOO)
    => true

    > The following works for constants that are already defined _only_ (which
    > is _not_ how Object and Kernel behave):
    >
    > class MyObject
    > MyKernel.constants.each do |c|
    > const_set(c, MyKernel.const_get(c))
    > end
    > end


    If I understand you correctly, you want all constants in MyKernel to be
    available in MyObject directly, even if the constants are added to
    MyKernel after after it is included in MyObject. If that is what you
    want, you'll probably have to use the MyKernel.included method to store
    a list of classes that include MyKernel, and override const_set on
    MyKernel to add the constants to those classes in addition to adding it
    to itself.

    Alternatively, if you want MyObject to have direct access to any
    constants in any included modules, you could override const_get on
    MyObject to check all included_modules if the constant isn't found in
    MyObject.

    I'm not sure why you would want to do either of those things, though.

    Jeremy
    --
    Posted via http://www.ruby-forum.com/.
     
    Jeremy Evans, Feb 29, 2008
    #10
  11. Paul Brannan

    Arlen Cuss Guest

    [Note: parts of this message were removed to make it a legal post.]

    On Fri, Feb 29, 2008 at 11:35 AM, Jeremy Evans <> wrote:

    > I think that Kernel and Object are special in that their constants are
    > available in the top level namespace. Other than there isn't much
    > difference between them and other classes in this case.


    The reason for that is since the top level namespace *is* an Object.

    >> self

    => main
    >> self.class

    => Object
    >>


    `main' is an instance of Object, hence everything we evaluate is just like
    it was evaluated in the instance method of any other Object. We have access
    to Object's constants, and Object includes Kernel, so Kernel's too.

    I'm not sure why you would want to do either of those things, though.
    >

    Indeed.


    > Jeremy
    >


    Cheers,
    Arlen.
     
    Arlen Cuss, Feb 29, 2008
    #11
  12. Paul Brannan

    Arlen Cuss Guest

    [Note: parts of this message were removed to make it a legal post.]

    Hi,

    On Fri, Feb 29, 2008 at 12:11 PM, Arlen Cuss <> wrote:

    > The reason for that is since the top level namespace *is* an Object.
    >


    Just to clarify everything else, this is the reason why they're available on
    every object. `Functions' defined on the top-level are actually *instance
    methods of Kernel*. This means that they're *included* as instance methods
    of Object, and hence of *every* object. Since Kernel is itself an Object,
    and it has a metaclass which is by all means an Object, this means you can
    even access them on Kernel as if they were module methods. Or any other
    object.

    >> def hi
    >> puts "hi!"
    >> end

    => nil
    >> (class << Kernel;self;end).hi

    hi!
    => nil
    >> Kernel.hi

    hi!
    => nil
    >> hi

    hi!
    => nil
    >> 42.hi

    hi!
    => nil
    >>


    Arlen
     
    Arlen Cuss, Feb 29, 2008
    #12
  13. Paul Brannan

    Arlen Cuss Guest

    [Note: parts of this message were removed to make it a legal post.]

    Guy,

    On Fri, Feb 29, 2008 at 10:53 PM, ts <> wrote:

    > No, not really. a function at toplevel is a private method of Object.


    Aha! Actually, it's great to see you reply to this entry. I've seen you
    comment in this list in the past on this topic (173746, 207801) which was
    part of my attempt to understand it all.

    For example #inspect is defined in Kernel, and you can write
    >
    > vgs% ruby -e 'def inspect() puts "Object#inspect"; super end; p 12;
    > 12.inspect'
    > Object#inspect
    > 12
    > -e:1:in `<main>'Object#inspect
    > : private method `inspect' called for 12:Fixnum (NoMethodError)
    > vgs%


    I see. If I try the way you do, I get the same result. If anything, this
    tells me I should be careful about using irb to work this stuff out, as it
    produces a different (!) result;
    >> def inspect(); puts "Object#inspect"; super end; p 12; 12.inspect

    Object#inspect
    12
    Object#inspect
    => "12"
    >>


    Guy Decoux
    >


    Cheers! :)
    Arlen
     
    Arlen Cuss, Feb 29, 2008
    #13
  14. Paul Brannan

    Paul Brannan Guest

    On Fri, Feb 29, 2008 at 08:48:50AM +0900, Arlen Cuss wrote:
    > 1. Foo is an instance of Object [eventually].
    > 2. Object mixes in Kernel.
    > 2.a. Kernel's constants are Object's too.


    Apparently all constants of modules mixed into Object belong to Object:

    irb(main):001:0> module M; FOO = 42; end
    => 42
    irb(main):002:0> class Object; include M; end
    => Object
    irb(main):003:0> class Foo; end
    => nil
    irb(main):004:0> Object.const_defined?:)M)
    => true
    irb(main):005:0> Foo.const_defined?:)M)
    => false

    The culprit:

    variable.c:1420 if (!recurse && klass != rb_cObject) break;

    > 3. Foo::SOME_CONST will see through to Object::SOME_CONST and then
    > that to Kernel::SOME_CONST.
    >
    > Correct me if I'm wrong in some detail.
     
    Paul Brannan, Mar 4, 2008
    #14
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    7
    Views:
    484
  2. Oodini
    Replies:
    1
    Views:
    1,822
    Keith Thompson
    Sep 27, 2005
  3. yogesh
    Replies:
    3
    Views:
    603
    Kenny McCormack
    Feb 12, 2006
  4. Replies:
    3
    Views:
    183
  5. Lars Gierth
    Replies:
    6
    Views:
    239
    David Masover
    Mar 20, 2010
Loading...

Share This Page