Constants defined in Kernel are also defined in Object?

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

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

···

On Fri, Feb 29, 2008 at 02:17:33AM +0900, Paul Brannan 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

Jeremy

···

--
Posted via http://www.ruby-forum.com/\.

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

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

Gregory Seidman 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

···

On Fri, Feb 29, 2008 at 06:08:38AM +0900, Joel VanderWerf wrote:

On Fri, Feb 29, 2008 at 02:17:33AM +0900, Paul Brannan 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

Arlen

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/\.

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

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.

···

On Fri, Feb 29, 2008 at 11:35 AM, Jeremy Evans <code@jeremyevans.net> wrote:

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

···

On Fri, Feb 29, 2008 at 10:30 AM, Joel VanderWerf <vjoel@path.berkeley.edu> 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

Hi,

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

···

On Fri, Feb 29, 2008 at 12:11 PM, Arlen Cuss <celtic@sairyx.org> wrote:

every object. `Functions' defined on the top-level are actually *instance
methods of Kernel*.

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

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%

Guy Decoux

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;

···

On Fri, Feb 29, 2008 at 08:48:50AM +0900, Arlen Cuss wrote:

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.

Guy,

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! :slight_smile:
Arlen

···

On Fri, Feb 29, 2008 at 10:53 PM, ts <decoux@moulon.inra.fr> wrote: