In this two-part blog post, I am going to discuss the programming concept of Delegation, how it applies in the Ruby programming language, and how it is related to the Delegator (and Forwardable) libraries in the Ruby Standard Library.
This topic really confused me when I first encountered it in the wild. It was not clear to me at first how the module Delegator (and similar modules, gems, and functions that accomplish delegation) relate to the actual concept of delegation.
Are delegation and Delegator the same thing? How are they related and why should I care? These are questions that I hope to clarify today.
I am a student at Launch School, an online Web Development program that encourages students to take the slow, methodical approach to learning, and pursue mastery at the expense of speed. And so in the spirit of mastery, I dove into documentation and related articles and learned quite a bit in the process.
The first article will discuss the concept of delegation in programming. We will continue in part 2 with our discussion of the
Forwardable libraries in Ruby.
Delegation is a generalized concept in programming that is particularly relevant to object-oriented programming. The wikipedia definition of delegation within the context of Object-Oriented Programming is as follows:
That sounds rather broad, doesn’t it? Immediately, familiar object-oriented concepts come to mind.
Indeed, as with many other terms, there is some debate as to when delegation stops and other programming concepts begin. Yet, it is sometimes listed as one of the important features of object-oriented approaches to programming, alongside encapsulation, inheritance and polymorphism.
One goal of this blog post, therefore, is to help you understand this concept if you happen to come across it.
In Launch School, in the Object Oriented Programming course, we learn about how to use inheritance, mixin modules, and collaborator objects, and these are all related to the concept of delegation in a broad sense. Let’s first go through these familiar concepts (covered in the Launch School OOP book if you need a refresher) and examine how they relate to our definition of delegation.
In class inheritance, a subclass defers method calls not defined in the subclass to the superclasses defined higher up its inheritance chain. The subclass, therefore, evaluates certain methods in the context of the superclass. In Ruby, classes are objects themselves, and so it is fair to say that class inheritance is a form of delegation, whereby one actor (the subclass or instance of a subclass) assigns a task to another actor (the superclass). Mixin modules are similar. In Ruby, Modules are also objects, and so Classes with mixin modules may be said to delegate certain functions to Modules that they “mix-in” to their method lookup structure.
Collaborator objects can help us achieve a particularly explicit and controlled form of delegation. With collaborator objects, the programmer must explicitly send to the object any method it wishes to delegate to that object. See the example below:
# Note: classes Scissors and Paper omitted for brevity.class Rock
"I'm a rock. I beat scissors and lose to paper."
attr_accessor :rock, :paper, :scissors
@rock = Rock.new
@paper = Paper.new
@scissors = Scissors.new
#=>"I'm a rock. I beat scissors and lose to paper."
#=>"I'm scissors. I beat paper and lose to rock."
So here we define three classes,
Game class, which instantiates instance objects with Rock, Paper and Scissors as collaborator objects.
To delegate to these collaborator objects, we must explicitly pass to them any method we wish to delegate. In this case, we wish to delegate to them the method call for
info with the line of code
This form of delegation can be quite powerful and is also explicit and limited in scope. By including these collaborator objects in our class structure, we gain access to the methods the collaborator objects have access to.
So now, hopefully, you have a better understanding of what delegation means and how the terminology applies to some of the fundamental object-oriented concepts we learned about in Launch School. Feel free to stop here if all you want is a basic introduction to the concept. That introduction above should be enough for you to understand generally what people are referring to if the topic of delegation comes up in a discussion or article elsewhere. However, Ruby provides us with an additional way to delegate between classes.
In part 2 of this two-part series, I will discuss the Delegator and Forwardable libraries (part of the Ruby Standard Library) and how you can use them to provide unique functionality, and also more logical organization and syntax to your code.