We know about classes and how they are an Object defined to “huddle up” like minded or similarly goal oriented objects (namely methods) and we know about class hierarchies, the perils that it imposes on our code through the thing called classical inheritance and how namespacing matters because the names we choose for our objects pose both rewards and great peril by threatening to pollute the global namespace.
So why am I bringing all this up?
Well, because it is time to take a closer look at our next great programming tool: Modules.
I’ll use this post as a starting point to branch out in a greater series of articles concerning Modules, why we need them, how to use them, benefits and limitations, among other things.
So what is a Module? I could tell you that a module is a part of a program. Or that it acts like a component of an application that shines at runetime. But in layman terms, a Module is just another way of grouping classes, methods and constants, objects that are like minded enough or serve the same purpose (work together to get the same job done). Mind you, it is only the Beholder (the author or user of the module and subsequent code) that determines that the Module is composed of code that serves the same purpose. The machine is oblivious to that fact. For it, it is all the same regardless.
If by now you’ve noticed the similarities between Modules and Classes, know that in Ruby for example the class Class is a subclass of the class Module. This means that every class object has the class as it’s parent (from which it inherits directly) and the Module as an ancestor (from which it inherits indirectly).
Now time for the differences. The most important one being that modules do not have instances. For you to grant it access to an instance you must specify that you desire to add the functionality of one particular module to the functionality of a class or a specific object. Think of it in terms of Module being the abstraction and Class being the specialization.
Okay, armed with that little bit of knowledge you’ll ask: “Why bother using them in the first place”?
The short answer is that modules exist to help you with program design and flexibility since modules (as the real world borrowed name implies) encourage modular design – a breaking apart, sorting and separating of large components into smaller, more manageable ones that you can use to mix and match object behavior.
Now if we already know that all objects “descend” from Object (which in turn descends from BasicObject) then this know that the majority of methods common to all objects (the base methods of the language) live – inside module Kernel.
Before I leave you hanging, let’s take just a quick look on how you define a Module.
module FriendlyModule def greet_reader puts “Hi there!” end end
So you do it just like you would define a class, albeit by substituting your starting definition of class for the keyword “module”.
But hold up just one second. We established that modules do not have instances. So how can we use our ExampleModule?
To use it, we’ll have to include it in a class object. Doing so we grant access in that class object to the the functionality existing in the Module, like so
class TheAuthor include FriendlyModule end ta = TheAuthor.new # instantiation ta.greet_reader # => “Hi there!”
We’ll go in deeper, but for now we’ll leave it at that. One last thing though. Modules that are included like such are sometimes referred to as “mix-ins”.