-2

In .NET, we have the types interface and class. There are a few relationships between these two types. In this example, we have all the relationships in .NET:

class Vehicle
{
}

interface IMovable
{
   void Move();
}

class Engine
{
}

class Car : Vehicle, IMovable
{
   private readonly Engine _engine;
   public Car(Engine engine) { _engine = engine; }

   public void Move() {}
}
  • Car extends Vehicle - a Car is-a Vehicle
  • Car implements IMovable - a Car can-do IMovable
  • Car needs an Engine to create itself - a Car has-a Engine

But I don't understand Ruby's modules because they have functionality but they aren't interfaces (in that they define method bodies, so they are more akin to subclassing), but they aren't superclasses (because multiple inheritance is not done in Ruby).

Can someone help me understand the usage of modules in Ruby and possibly give an analogy to .NET?

EDIT: Seeing the 3 votes to close due to duplicate, I must clarify. I am asking what is the relationship between classes and modules (given that classes implementing interfaces is can-do in .NET). The 'duplicate' answer does NOT address that question.

Dan
  • 10,282
  • 2
  • 37
  • 64

2 Answers2

5

Modules can be used for two things in Ruby: as namespaces for constants and as mixins.

The namespace usage is quite similar to C# namespaces: a module can contain constants (and all constants are contained in modules, even if you don't explicitly see it, in which case they belong to Object) which are namespaced to that module. So, Foo::BAR and Baz::BAR are two different constants even though they have the same name.

Mixins are a bit trickier. One way to look at a mixin, is that a mixin is a class which doesn't know its superclass (or a class that is parameterized by its superclass). Okay, this sounds a bit convoluted. Let's look at an example.

Imagine, something like this were possible in C#:

interface IEachable<E> {
  IEachable<E> Each(Action<E> block);
}

class Enumerable<S, E> : S where S : IEachable<E> {
  List<T> Map(Func<E, T> block) {
    var res = new List<T>();
    this.Each(e => {†res.Add(block(e));});
    return res;
  }
}

So, you have a generic class Enumerable which inherits from its type parameter S (the superclass). This is actually a pretty accurate description of the Enumerable mixin in Ruby. Everytime you instantiate the generic class into a concrete type, it ends with a different superclass.

So, the same class appears multiple times in the inheritance hierarchy, each time with a different superclass, but always just one.

This is different from multiple inheritance, where the same class appears once in the inheritance hierarchy, with multiple superclasses.

This property, that the class always has just one superclass, is called linearization and it solves a lot of the problems that traditional multiple inheritance has, which are usually related to the fact that there are multiple possible paths between two classes in the inheritance DAG, whereas with mixin linearization, there is just an inheritance tree, so there is always just one possible path.

In particular, this is what happens, when you mix a module M into a class C with superclass S:

module M; end

class C < S
  include M
end

When you call include, Ruby will

  1. create a new class M' whose method table pointer, constant table pointer, class variable table pointer and instance variable table pointer point to M's method table, constant table, class variable table and instance variable table
  2. set M''s superclass to C's current superclass (i.e. S)
  3. set C's superclass to M'

So that the inheritance hierarchy now looks like this:

C < M' < S

[Note: Actually include delegates to append_features, which really does the above work, and just like almost everything else in Ruby, you can actually alter this behavior by overriding append_features, but that is advanced meta-magic.]

So, what are the practical implications of having a class that can be used in multiple places in the inheritance hierarchy? Well, you can use it to implement common behavior for unrelated classes.

Again, look at the Enumerable mixin: it provides common behavior for any object that conforms to the following protocol: it must have an each method that yields all elements one-by-one and returns self. That's it. There doesn't need to be any sort of inheritance relationship between the classes of those objects. All that is required is that they respond to each in an appropriate manner.

Which leads us to your question about interfaces: that's an interface. Although in Ruby, we usually call it protocol. Protocols in Ruby are very much like interfaces in C#, however, there is one crucial difference: there is no such thing as a protocol in Ruby. Protocols are latent, not manifest, they only exist in the programmer's head, in documentation, but not in the source code, and thus they cannot be checked by the language.

Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653
0

I came from .NET as well so I had the same doubt that you have now. The short answer is that there is not such a "module" concept in a language like C# or Java. The idea of Ruby modules is to have reusable code to include or extend functionality across different classes. This article explains very well the mixin concept:

A mixin is a way for code to be shared across multiple classes and is closely related to duck typing.

Once you learn the mixin and duck typing concepts, you will understand perfectly the Ruby philosophy. This book from Sandi Metz explain in details all of these OOP concepts but with a Java/C# perspective. It was after reading it that all the new Ruby concepts made sense to me.

Rafa Paez
  • 4,820
  • 18
  • 35