Kernel's module methods?

  • Follow


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?
-- 
Posted via http://www.ruby-forum.com/.

0
Reply bbxx789_05ss (1895) 8/6/2009 11:02:06 AM

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
-- 
Posted via http://www.ruby-forum.com/.

0
Reply b.candler (2627) 8/6/2009 11:58:44 AM


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

2009/8/6 Brian Candler <b.candler@pobox.com>

> 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 Coglan
http://jcoglan.com

0
Reply jcoglan (199) 8/6/2009 12:16:36 PM

James Coglan 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?
-- 
Posted via http://www.ruby-forum.com/.

0
Reply b.candler (2627) 8/6/2009 12:32:10 PM

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

2009/8/6 Brian Candler <b.candler@pobox.com>

> James Coglan 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?


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/
=> []


> 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?


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.

--
James Coglan
http://jcoglan.com

0
Reply jcoglan (199) 8/6/2009 12:43:08 PM

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

> James Coglan 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?

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 Gray II


0
Reply james8284 (4404) 8/6/2009 12:46:38 PM

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

2009/8/6 James Gray <james@grayproductions.net>

> On Aug 6, 2009, at 7:32 AM, Brian Candler wrote:
>
>  James Coglan 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?
>>
>
> 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.


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.

--
James Coglan
http://jcoglan.com

0
Reply jcoglan (199) 8/6/2009 1:12:50 PM

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

> 2009/8/6 James Gray <james@grayproductions.net>
>
>> On Aug 6, 2009, at 7:32 AM, Brian Candler wrote:
>>
>> James Coglan 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?
>>>
>>
>> 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.
>
>
> 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.

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 Gray II

0
Reply james8284 (4404) 8/6/2009 1:16:08 PM

James Coglan 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"]
-- 
Posted via http://www.ruby-forum.com/.

0
Reply b.candler (2627) 8/6/2009 1:49:14 PM

James Gray 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.

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

0
Reply vjoel (2600) 8/6/2009 4:32:12 PM

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

> James Gray 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(r)
     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(r)
     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 Gray II

0
Reply james8284 (4404) 8/6/2009 6:53:22 PM

10 Replies
39 Views

(page loaded in 0.146 seconds)

Similiar Articles:













7/23/2012 1:27:34 PM


Reply: