Why does the Ruby module Kernel exist?
Ideally,
- Methods in spirit (that are applicable to any object), that is, methods that make use of the receiver, should be defined on the
Object
class, while - Procedures (provided globally), that is, methods that ignore the receiver, should be collected in the
Kernel
module.
Kernel#puts
, for example doesn't do anything with its receiver; it doesn't call private methods on it, it doesn't access any instance variables of it, it only acts on its arguments.Procedures in Ruby are faked by using Ruby's feature that a receiver that is equal to self
can be omitted. They are also often made private to prevent them from being called with an explicit receiver and thus being even more confusing. E.g., "Hello".puts
would print a newline and nothing else since puts
only cares about its arguments, not its receiver. By making it private, it can only be called as puts "Hello"
.
In reality, due to the long history of Ruby, that separation hasn't always been strictly followed. It is also additionally complicated by the fact that some Kernel
methods are documented in Object
and vice versa, and even further by the fact that when you define something which looks like a global procedure, and which by the above reasoning should then end up in Kernel
, it actually ends up as a private instance method in Object
.
What is the purpose of `Kernel`?
I'll start with a question: what would self
be inside a typical Kernel
method such as puts
? The closest thing to a meaningful self
inside puts
would probably be the Ruby runtime itself. Similarly for other "methods that really want to be functions" like Array
or fork
. So you can look at Kernel
as a dumping ground for methods that are, more or less, commands or messages to Ruby itself.
Kernel
also has odd methods like sub
and chop
that are really only useful for one-off ruby -e
scripts. These things tend to use $_
as an implied self
but I think they can be considered as special cases of the "commands to the Ruby runtime" as above.
Where does a method go when you want to be able to call that method on any object? I'd say that it would go into Object
. If the method is really a function in disguise and has no meaningful self
, then it would go into Kernel
.
Why am I able to use Kernel singleton methods like `puts`?
You are looking in the wrong place.
Methods like Kernel#Array
, Kernel#Complex
, Kernel#Float
, Kernel#Hash
, Kernel#Integer
, Kernel#Rational
, Kernel#String
, Kernel#__callee__
, Kernel#__dir__
, Kernel#__method__
, Kernel#`
, Kernel#abort
, Kernel#at_exit
, Kernel#autoload
, Kernel#autoload?
, Kernel#binding
, Kernel#block_given?
, Kernel#callcc
, Kernel#caller
, Kernel#caller_locations
, Kernel#catch
, Kernel#eval
, Kernel#exec
, Kernel#exit
, Kernel#exit!
, Kernel#fail
, Kernel#fork
, Kernel#format
, Kernel#gets
, Kernel#global_variables
, Kernel#initialize_clone
, Kernel#initialize_copy
, Kernel#initialize_dup
, Kernel#iterator?
, Kernel#lambda
, Kernel#load
, Kernel#local_variables
, Kernel#loop
, Kernel#open
, Kernel#p
, Kernel#pp
, Kernel#print
, Kernel#printf
, Kernel#proc
, Kernel#putc
, Kernel#puts
, Kernel#raise
, Kernel#rand
, Kernel#readline
, Kernel#readlines
, Kernel#require
, Kernel#require_relative
, Kernel#select
, Kernel#set_trace_func
, Kernel#sleep
, Kernel#spawn
, Kernel#sprintf
, Kernel#srand
, Kernel#syscall
, Kernel#system
, Kernel#test
, Kernel#throw
, Kernel#trace_var
, Kernel#trap
, Kernel#untrace_var
, and Kernel#warn
don't do anything useful with their receiver. They don't call private methods, they don't access instance variables, they in fact completely ignore what self
is.
Therefore, it would be misleading if you call them like this:
foo.puts 'Hello, World!'
Because a reader would be mislead into thinking that puts
does something with foo
, when in fact, it completely ignores it. (This applies especially to the printing family of methods, because there also exist IO#puts
and friends, which indeed do care about their receiver.)So, in order to prevent you from misleadingly calling these methods with a receiver, they are made private
, which means they can only be called without an explicit receiver. (Obviously, they will still be called on self
, but at least that won't be so obvious visually.)
Technically, these aren't really methods at all, they behave more like procedures, but Ruby doesn't have procedures, so this is the best way to "fake" them.
The reason why they are also defined as singleton methods is so that you can still call them in contexts where Kernel
is not in the inheritance hierarchy, e.g. something like this:
class Foo < BasicObject
def works
::Kernel.puts 'Hello, World!'
end
def doesnt
puts 'Hello, World!'
end
end
f = Foo.new
f.works
# Hello, World!
f.doesnt
# NoMethodError: undefined method `puts' for #<Foo:0x00007f97cf918ed0>
And the reason why they need to be defined separately at all is that the instance method versions are private
. If they weren't, then you would simply be able to call Kernel.puts
anyway, because Object
includes Kernel
and Kernel
is an instance of Module
which is a subclass of Object
, thus Kernel
is an indirect instance of itself. However, the methods are private
and thus you would get aNoMethodError: private method `puts' called for Kernel:Module
instead. Therefore, they need to be duplicated separately. There is actually a helper method that does that: Module#module_function
. (This is also used for Math
, where you can either call e.g. Math.sqrt(4)
or include Math; sqrt(4)
. In this case, you have the choice of include
ing Math
or not, whereas Kernel
is pre-include
d in Object
always.)So, in summary: the methods are duplicated as private
instance methods of Kernel
as well as public
singleton methods (which is really just instance methods of Kernel
's singleton class). The reason they are defined as private
instance methods is so they cannot be called with an explicit receiver and are forced to look more like procedures. The reason they are duplicated as singleton methods of Kernel
is so that they can be called with an explicit receiver as long as that explicit receiver is Kernel
, in contexts where Kernel
is not available in the inheritance hierarchy.
Check this out:
#ruby --disable-gems --disable-did_you_mean -e'puts Kernel.private_instance_methods(false).sort'
Array
Complex
Float
Hash
Integer
Rational
String
__callee__
__dir__
__method__
`
abort
at_exit
autoload
autoload?
binding
block_given?
caller
caller_locations
catch
eval
exec
exit
exit!
fail
fork
format
gets
global_variables
initialize_clone
initialize_copy
initialize_dup
iterator?
lambda
load
local_variables
loop
open
p
pp
print
printf
proc
putc
puts
raise
rand
readline
readlines
require
require_relative
respond_to_missing?
select
set_trace_func
sleep
spawn
sprintf
srand
syscall
system
test
throw
trace_var
trap
untrace_var
warn
ruby, kernel module methods documentation
The class Object
itself is an object. When Kernel
is included in Object, its instance methods become instance methods of Object
, but also instance methods of the object Object
(a.k.a class methods of Object). Yes, that means that the object Object
has Object
in its class' ancestor chain.
Object.class.ancestors
# => [Class, Module, Object, Kernel, BasicObject]
Ruby Kernel#autoload and Module#autoload difference
As it might be seen in source code of these methods in standard documentation, Kernel#autoload
calls Module#autoload
after casting the receiver to it’s class.
When one uses the most common approach and calls autoload
on the class level:
class C
autoload(:M, 'm')
end
the Module#autoload
is called because Class < Module
. Since the receiver is in this case already a Class
’ instance, there is no necessity in explicit cast.On the other hand, one might need to call autoload
within a method body:
class C
def c
autoload(:M, 'm')
end
end
In the latter case the receiver is an instance, and unless it’s a Module
descendant, Kernel#autoload
is called, which, in turn, retrieves the class of this instance and passes the call to it’s Module#autoload
. ruby Kernel: method behaves as instance method
1.9.3-p327 :002 > Kernel.private_instance_methods.grep /^print/
=> [:printf, :print]
instance_methods
only gives you a list of public instance methods. Since Kernel
is included by Object
, its private instance methods are always available, so there's no need to make them public. How do I tell which modules have been mixed into a class?
Try:
MyClass.ancestors.select {|o| o.class == Module }
for example:>> Array.ancestors.select {|o| o.class == Module}
=> [Enumerable, Kernel]
UPDATETo get the modules mixed into an object instance at runtime you'll need to retrieve the eigenclass of the instance. There is no clean way to do this in Ruby, but a reasonably common idiom is the following:
(class << obj; self; end).included_modules
If you find yourself using this a lot, you can make it generally available:module Kernel
def eigenclass
class << self
self
end
end
end
and the solution is then:obj.eigenclass.included_modules
Ruby Class namespacing with modules: Why do I get NameError with double colons but not module blocks?
It may seem counter-intuitive, but constant lookup in Ruby is done using current lexical scope, i.e. the current lexical nesting level (location in the source code), not the semantic nesting level.
This can be tested by inspecting Module.nesting
, which prints the current lexical scope:
class Foo::SecondClass
pp Module.nesting # -> [Foo::SecondClass]
end
module Foo
class SecondClass
pp Module.nesting # -> [Foo::SecondClass, Foo]
end
end
Since Ruby uses this nesting level for symbol lookup, it means in the situation where you try to look up FirstClass
within nesting [Foo::SecondClass]
, Ruby will not find it. However when you try to look it up within nesting [Foo::SecondClass, Foo]
, it will find FirstClass
under Foo
, just like you expect.
To get around this, you could do:
class Foo::SecondClass
def meth
Foo::FirstClass.new.meth
end
end
Which will now work as you expect, since you provided the necessary lookup hint for FirstClass
, and told Ruby it is inside Foo
. Module instance methods and Module regular methods in Ruby
This might clarify things:
▶ module Test
▷ def im; end
▷ def mm; end
▷ module_function :mm
▷ end
▶ Test.methods(false) # false to not output inherited
#⇒ [
# [0] mm() Test
# ]
▶ Test.instance_methods(false) # false to not output inherited
#⇒ [
# [0] :im
# ]
▶ Test.im
#⇒ NoMethodError: undefined method `im' for Test:Module
# from (pry):99:in `__pry__'
▶ Test.mm
#⇒ nil # fine, called
Module methods might be called as is, as seen above. For instance methods, one needs an instance:▶ "Hello world!".extend(Test).im
#⇒ nil # fine, called
Related Topics
Ruby Symbols Are Not Garbage Collected!? Then, Isn't It Better to Use a String
How to Restrict Markdown Syntax in Ruby
Where Is Ruby's Erb Format "Officially" Defined
Get Value from String Representing Local Variable
Problem with Vim's Ruby Plugin
Gitlab Configuration Issues:: Nginx Unicorn Port Conflict
Fastest Way to Skip Lines While Parsing Files in Ruby
Outputting Stdout to a File and Back Again
How to Access Sinatra App on Host Machine with Vagrant Forwarded Ports
How to Declare a Two-Dimensional Array in Ruby
Command Not Found/Install Missing Gem Binaries with 'Bundle Install' Using Autotest
Should I Move My Custom Methods to Model from Controller
One or More Params in Model Find Conditions with Ruby on Rails
Gem Install Pg for Ruby on Rails
Access an Instance Variable from Child Classes
Statically Compile Pdftk for Heroku. Need to Split PDF into Single Page Files