Modules Part I - Enter the Include Class

Modules in Ruby serve two purposes. One is to provide namespace scope for code organization seen in the syntax Test::Unit::TestCase, where TestCase is a class defined inside of the Unit module, which is in turn defined within the Test module. The second purpose of modules is to provide a method for code reuse which falls somewhere between abstract base classes and multiple inheritance. This post explores the implementation and consequences of this second purpose.

A module which defines code that will be shared by other modules or classes is known as a Mixin. Mixing a module into a class is generally done with a call to the include method.

A call to the ancestors of NeedALittleHelp will confirm that Useful has been inserted into NeedALittleHelp’s inheritance chain

The inheritance chain might be drawn as…

An included module will always be inserted into the inheritance chain below a declared super class.

It’s worth pointing out that a single inheritance chain has been preserved. The include method has simply manipulated Klass’s inheritance chain by inserting the MixinModule module between the class and it’s super…

It’s possible to mix multiple modules into a class as below.

Once again the Klass’s inheritance chain has been manipulated so that the super of Klass now points to AnotherMixin whose super points to MixinModule…

This raises the question of what occurs when these modules are included into a new class in reverse order…

Here the super of MixinModule is pointing to AnotherMixin. This is odd behavior…

It would seem that the super pointer of a module can point to different places depending on context. Clearly include cannot be altering the super pointer of the actual module it acts on, as the order in which a class includes the module can result in differing inheritance chains. At the same time, it’s convenient for there to be only once actual instance of a module to allow for minimal overhead in updating the module’s method table. Ruby solves this problem with something called an Include Class. When a module is included into a class (or module), a new class is created on the fly. The method table of this class is a pointer to the included modules method table. This ensures that each class that includes a module has a “copy” of the module who’s super pointer is free for manipulation. Since the method table is a pointer to the one true method table for the module, updates to the modules methods are shared between all “copies” of the module. This module “copy” is an Include Class.

The code below is a simplified version of the C function for creating a new include class.

As described above a new object is created of type T_ICLASS which is the C struct for storing include classes. A pointer to the method table of of the module is copied to the include class. On the next line the super for the include class is set to the super class passed into the function as a parameter. The class pointer for the new class is set to the module which has been copied. This reference to the actual module is is useful for the case, as in the ancestor method call above, where the interpreter needs to know the module associated with the include class. This does mean that, unlike other classes, the class of an include class is not a metaclass. We’ll discuss the implications of this when looking at including class methods. A better diagram of the NeedALittleHelp inheritance chain might look like this…

The next post will continue to explore modules and includes class. We’ll dig deeper into implementation and cover some of the nuances of inheritance chain manipulation. As always thanks for reading and feel free to leave comments with questions, corrections, or haiku.

WordPress database error: [Table 'geyerindustriesblog.wp_comments' doesn't exist]
SELECT * FROM wp_comments WHERE comment_post_ID = '15' AND comment_approved = '1' ORDER BY comment_date

Comments are closed.