Kernel's module methods?

According to pickaxe2, p516:

Module Kernel

The Kernel module is included by class Object, so its [instance] methods
are available in every Ruby object. The Kernel instance methods are
documented in class Object beginning on page 567. This section
documents the module methods. These methods are called without a
receiver and thus can be called in functional form.

I tried to model that state of affairs with this code:

module K
def K.test1
puts “test1”
end

def test2
puts “test2”
end
end

class O
include K

K.test1

test1
end

–output:–
test1
r2test.rb:16: undefined local variable or method `test1’ for O:Class
(NameError)

How come you can call Kernel methods without a receiver?

7stud – wrote:

How come you can call Kernel methods without a receiver?

If I understand it rightly: because self is the top level object ‘main’,
and main is an instance of Object.

self
=> main

self.class
=> Object

module K
def test2
puts “test2”
end
end
=> nil

class Object; include K; end
=> Object

test2
test2
=> nil

2009/8/6 Brian C. [email protected]

7stud – wrote:

How come you can call Kernel methods without a receiver?

If I understand it rightly: because self is the top level object ‘main’,
and main is an instance of Object.

I think the point being raised is that when you mix a module into a
class,
the class gains the module’s instance methods, but not its
module/singleton
methods. So it seems that the only way you’d be able to call Kernel’s
module
methods without a receiver would be if self were equal to Kernel.
But
seeing as how you can call these methods sans receiver anywhere in your
program, I assume the Kernel methods are given special treatment and
don’t
follow the usual scoping rules for method calls.

Another way you could do this is by having all objects inherit from
Kernel’s
eigenclass, but that’s also not allowed in user code so again this
points at
special treatment of Kernel code in the Ruby VM.

James C. wrote:

I think the point being raised is that when you mix a module into a
class,
the class gains the module’s instance methods, but not its
module/singleton
methods. So it seems that the only way you’d be able to call Kernel’s
module
methods without a receiver would be if self were equal to Kernel.

Yes, but are you sure they are module methods, not just instance
methods?

But
seeing as how you can call these methods sans receiver anywhere in your
program, I assume the Kernel methods are given special treatment and
don’t
follow the usual scoping rules for method calls.

Everywhere in your program, you are inside some instance of Object (or a
subclass of Object). And therefore self is that object, and that object
inherits Kernel’s instance methods. e.g.

class Foo
def bar
puts “hello”
end
end

foo = Foo.new
foo.bar

The ‘puts’ inside method :bar is calling foo.puts. Since you haven’t
defined your own instance method ‘puts’ in the Foo class, then it
follows the class hierarchy back up to Kernel. No special casing
involved.

That is: AFAICS, this would make sense as long as foo were an instance
method of module Kernel, not a module/singleton method.

Also note:

foo.puts #=> private method `puts’ called for #Foo:0x82d875c

So it seems ‘puts’ is an instance method of our class, albeit a private
one.

Or have I got this completely wrong?

2009/8/6 Brian C. [email protected]

methods?
Yes, for example puts is a singleton method on Kernel:

module Kernel
def metaclass
class << self; self; end
end
end

Kernel.metaclass.instance_methods(false).grep /puts/
=> [“puts”]
Kernel.instance_methods(false).grep /puts/
=> []

In fact, puts does not even appear as an instance method on Object:

Object.instance_methods.grep /puts/
=> []

class Foo
follows the class hierarchy back up to Kernel. No special casing
one.

Or have I got this completely wrong?

It seems privacy might explain it, since that would stop it showing up
in my
above example.

class Foo
def p
method :puts
end
end

Foo.new.p
=> #<Method: Foo(Kernel)#puts>

So that puts method is coming from Kernel, even though it doesn’t
appear
in Kernel.instance_methods. This would suggest that all the Kernel
module
methods are in fact private instance methods of Kernel (making them
callable from any object), but the Kernel module exposes public
singleton
versions of all of them. If this is true the Pickaxe explanation is a
little
back-to-front.

On Aug 6, 2009, at 7:32 AM, Brian C. wrote:

methods?
They are “module functions” actually, implemented with this:

------------------------------------------------- Module#module_function
module_function(symbol, …) => self

  Creates module functions for the named methods. These functions
  may be called with the module as a receiver, and also become
  available as instance methods to classes that mix in the module.
  Module functions are copies of the original, and so may be changed
  independently. The instance-method versions are made private. If
  used with no arguments, subsequently defined methods become module
  functions.

     module Mod
       def one
         "This is one"
       end
       module_function :one
     end
     class Cls
       include Mod
       def callOne
         one
       end
     end
     Mod.one     #=> "This is one"
     c = Cls.new
     c.callOne   #=> "This is one"
     module Mod
       def one
         "This is the new one"
       end
     end
     Mod.one     #=> "This is one"
     c.callOne   #=> "This is the new one"

James Edward G. II

2009/8/6 James G. [email protected]

methods without a receiver would be if self were equal to Kernel.


Creates module functions for the named methods. These functions
may be called with the module as a receiver, and also become
available as instance methods to classes that mix in the module.
Module functions are copies of the original, and so may be changed
independently. The instance-method versions are made private. If
used with no arguments, subsequently defined methods become module
functions.

Thanks for pointing that out, I wasn’t aware of it. Reminds me of a neat
trick for adding a module’s instance methods to the same module as
singleton
methods:

module MyMod
extend self
end

Any instance methods from MyMod (and modules it includes) will appear as
singleton methods on the MyMod object. It differs from #module_function
in
that the methods are not copied, so if you change MyMod#foo, MyMod.foo
will
be updated to reflect the new method.

On Aug 6, 2009, at 8:12 AM, James C. wrote:

methods. So it seems that the only way you’d be able to call
They are “module functions” actually, implemented with this:
used with no arguments, subsequently defined methods become module
extend self
end

Any instance methods from MyMod (and modules it includes) will
appear as
singleton methods on the MyMod object. It differs from
#module_function in
that the methods are not copied, so if you change MyMod#foo,
MyMod.foo will
be updated to reflect the new method.

Yes, and I generally prefer extend(self) to module_function after much
time trying it both ways. Unfortunately, I always seem to eventually
run into issues after using module_function, say with constant
resolution or included modules (like you mentioned).

James Edward G. II

James G. wrote:

Yes, and I generally prefer extend(self) to module_function after much
time trying it both ways. Unfortunately, I always seem to eventually
run into issues after using module_function, say with constant
resolution or included modules (like you mentioned).

Can you post an example of the constant resolution problem next time you
come across it? I’m curious because I’m in the habit of using
module_function rather than extend(self), not for any good reason except
that it is perhaps more self documenting.

James C. wrote:

In fact, puts does not even appear as an instance method on Object:

Object.instance_methods.grep /puts/
=> []

but:

irb(main):001:0> Object.private_instance_methods.grep(/puts/)
=> [“puts”]

On Aug 6, 2009, at 11:32 AM, Joel VanderWerf wrote:

James G. wrote:

Yes, and I generally prefer extend(self) to module_function after
much time trying it both ways. Unfortunately, I always seem to
eventually run into issues after using module_function, say with
constant resolution or included modules (like you mentioned).

Can you post an example of the constant resolution problem next time
you come across it? I’m curious because I’m in the habit of using
module_function rather than extend(self), not for any good reason
except that it is perhaps more self documenting.

Here’s an example I remember from just the other day (though it
probably falls more under the included module problem). Consider this
simple module:

module MoreMath
extend Math # needed for self::sqrt
include Math # needed for self#sqrt and PI

module_function

def circ®
2 * PI * r
end

def dist(x1, y1, x2, y2)
sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
end
end

p MoreMath.circ(12)
p MoreMath.dist(0, 0, 3, 4)

Note that I need both an extend and include to get just that much to
work. Or, I can just do:

module MoreMath
include Math
extend self

def circ®
2 * PI * r
end

def dist(x1, y1, x2, y2)
sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
end
end

p MoreMath.circ(12)
p MoreMath.dist(0, 0, 3, 4)

Anyway, I too like module_function() and have used it a lot. I like
how it makes the instance methods private so they don’t add to an
object’s public interface when mixed in.

It just seems like I have more control with extend(self) so I tend to
reach for that now.

James Edward G. II