7

In the book OO Design in Ruby, Sandi Metz says that the main use of modules is to implement duck types with them and include them in every class needed. Why is the Ruby Kernel a module included in Object? As far as I know it isn't used anywhere else. What's the point of using a module?

sawa
  • 165,429
  • 45
  • 277
  • 381
Shimu
  • 1,137
  • 11
  • 25
  • I think you are right it probably would not be considered ideal OO design, and it's probably a mistake to go looking for reasons to justify it. – jrochkind Jul 10 '16 at 15:47
  • 1
    Is this is just [What is the purpose of Kernel?](http://stackoverflow.com/q/22926586/479863) all over again? – mu is too short Jul 10 '16 at 17:09
  • You're right, it's pretty much anti-OO. `Kernel` contains all those "procedures" that exist for convencience and ignore their receiver (i.e. don't do anything with `self`). – Jörg W Mittag Jul 10 '16 at 17:10
  • How is it not ideal OO design? (1) Sandi Metz is not the final authority on the use of modules. (2) Anyway she said this is ***main use*** not the definitive use. (3) If you were Matz, would you create a completely separate means of putting those methods in Object, when you already had module as a feature of Ruby? – iconoclast Aug 21 '23 at 15:24

2 Answers2

7

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.

Wand Maker
  • 18,476
  • 8
  • 53
  • 87
Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653
6

As you already pointed out: Modules provide a way to collect and structure behavior, so does the Kernel module. This module is mixed in early into the class Object so every Ruby class will provide these methods. There is only a BasicObject before in hierarchy, it's child Objects purpose is only to get extended by the Kernel methods. BasicObject has only 7 methods that very very basic like new, __send__ or __id__.

class Object < BasicObject
  include Kernel # all those many default methods we appreciate :)
end
unused
  • 796
  • 4
  • 12