Wednesday, October 12, 2011

Modules and Mixins

Many built-in methods are available from class ancestors. Of special note are the Kernel methods mixed-in to the Object superclass; because Object is universally available, the methods added to it from Kernel are also universally available. These methods form an important part of Ruby.

The terms module and mixin are nearly synonymous. A module is a collection of methods and constants that is external to the Ruby program. It can be used simply for namespace management, but the most common use of a module is to have its features "mixed" into a class (by using include). In this case, it is used as a mixin.

This term was apparently borrowed most directly from Python. (It is sometimes written as mix-in; but we write it as a single word.) It is worth noting that some LISP variants have had this feature for more than two decades.
Do not confuse this usage of the term module with another usage common in computing. A Ruby module is not an external source or binary file (though it may be stored in one of these). A Ruby module instead is an OOP abstraction similar to a class.
An example of using a module for namespace management is the frequent use of the Math module. To use the definition of pi, for example, it is not necessary to include the Math module; you can simply use Math::PI as the constant.

A mixin is a way of getting some of the benefits of multiple inheritance without dealing with all the difficulties. It can be considered a restricted form of multiple inheritance, but the language creator Matz has called it single inheritance with implementation sharing.
Note that include appends features of a namespace (a module) to the current space; the extend method appends functions of a module to an object. With include, the module's methods become available as instance methods; with extend, they become available as class methods.

We should mention that load and require do not really relate to modules but rather to nonmodule Ruby sources and binaries (statically or dynamically loadable). A load operation essentially reads a file and inserts it at the current point in the source file so that its definitions become available at that point. A require operation is similar to a load, but it will not load a file if it has already been loaded.
The Ruby novice, especially from a C background, may be tripped up by require and include, which are basically unrelated to each other. You may easily find yourself doing a require followed by an include to use some externally stored module.

No comments:

Post a Comment