The Gang of Four is wrong and you don't understand delegation

by Jim Gay

The Gang of Four got it wrong. Ruby’s standard library has it wrong. Rails has it wrong.

Is it still wrong if everyone is doing it?

Yes.

The Gang of Four book Design Patterns gives us common vocabulary to understand basic patterns in Object-oriented programming. It helps all of us use the same terms when discussing our software and prevents confusion.

Sadly, this book seems to cause a whole hell of a lot of confusion.

They say “prefer composition over inheritance.” That’s great, there’s good reason for that.

They say to use “delegation.” That’s great. Although there’s not a single example of delegation in their book.

I do not think it means what you think it means Delegation is a technique often cited as a way to create flexibility in your programs. That is to say, delegation is often given as the way to composition.

But delegation isn’t what you think it is. The Gang of Four have lead you astray.

Worse still, almost every reference you’ll find for “delegation” shows you examples of just object collaboration with message forwarding. They are examples of plain old method calls and not delegation.

Now imagine what your mentor would say about understanding basic programming concepts…

Don’t have a mentor? That’s ok. Imagine that you do. Now imagine what your mentor would say about understanding basic programming concepts…

You should probably understand them correctly, right?

So what is Delegation?

Delegation is easy to understand but we’re so used to hearing and reading it in reference to something else. Let’s fix that.

Henry Lieberman coined the term “delegation” in Using prototypical objects to implement shared behavior in object-oriented systems released with the OOPLSA ‘86 Conference proceedings on Object-oriented programming systems, languages and applications. That content is behind a pay wall, but you can read similar and updated content on his website

In there, you’ll find exactly what delegation is, but I’m not sending you away to pore over another long article; I can simplify it for you. When you have time, however, go read Lieberman’s own words.

Lieberman discussed this in terms of a GUI drawing tool. Here’s the key idea behind delegation:

When a pen delegates a draw message to a prototypical pen, it is saying “I don’t know how to handle the draw message. I’d like you to answer it for me if you can, but if you have any further questions, like what is the value of my x variable, or need anything done, you should come back to me and ask.” If the message is delegated further, all questions about the values of variables or requests to reply to messages are all inferred to the object that delegated the message in the first place.

In short, when you send a message to an object, it has a notion of “self” where it can find attributes and other methods. When that object delegates to another, then any reference to “self” always refers to the original message recipient. Always.

The other inheritance

Class-based inheritance isn’t the only game in town. Prototype-based inheritance is another way to structure your objects for behavior sharing. One approach sets behaviors in an abstract location (the class) and another sets it on instances (the objects).

Self is a programming language which implements what Lieberman defines. Self has objects which contain slots. Each slot can contain a method, or a reference to a prototype object in a parent slot. If an object received a message it didn’t understand, it could delegate to an object in its parent slot.

This is prototypical inheritance, not class inheritance. It is similar, although not the same, as saying that an object has a class (like Ruby objects) which contains additional behavior.

Self giving us objects with a parent slot is he equivalent of JS giving us an object with a prototype reference.

JS is the most popular prototype-based language and is much easier for you to try, so rather than teach you Self, we’ll look at JS. You can even open up your browser’s console and try this out right now.

In JS we can assign a prototype: the equvalent of the parent slot in Self.

function Container(){};
Container.prototype = new Object();
Container.prototype.announce = function(){ alert("these are my things: " + this.things) };

function Bucket(things){this.things = things};
Bucket.prototype = new Container();

bucket = new Bucket("planes, trains, and automobiles")
bucket.announce() // alerts "these are my things: planes, trains, and automobiles"

In delegation parlance the bucket object is the client which forwards a message to the delegate.

In the above example, you can see that the evaluation of this.things was done in the context of the client object. When we called the announce function, it was found on the delegate object. When the function was evaluated, this refered to the client.

When a JS object’s prototype contains a functon, the function is evaluated as if the object has that method. The first example showed that this (which is just self in JS) always referred to the original message recipient.

What about Ruby?

First, understand forwarding. Forwarding is passing a message from one object to another. The Ruby standard library forwardable is aptly named and allows you to forward messages from one object to another.

Now, let’s take the poorly named delegate library from the Ruby standard library which also allows you to forward messages from one object to another.

require 'delegate'

# assuming we have a Person class with a name method
person = Person.new(:name => 'Jim')

class Greeter < SimpleDelegator
  def hello
    "Hi! I'm #{name}."
  end
end

greeter = Greeter.new(person)

greeter.hello #=> "Hi! I'm Jim."

What happens inside that Greeter is that when the greeter instance is initialized it contains a reference to the person. When an unknown method is called, it is forwarded to the target object (which is person). Remember, we’re still looking at the delegate library, which helps us forward messages… Confused? Yeah, I was too. So, it seems, is the rest of the world.

Forwarding is just the passing of a message to an object: a method call.

The difference between this and delegation is that these libraries allow you to easily forward messages to additional objects, rather than executing the method of another object in the context of the first like we saw with prototype-based inheritance in JS.

We are often barely aware of this because Ruby’s method_missing power does the trick in SimpleDelegator. We think about methods automagically going to the object we want.

Even though our Greeter method refers to self, the message is forwarded to the other object and handled there when, of course, the method is missing on the client.

If we want to share behavior without extending an object with additional methods, then method_missing and/or SimpleDelegator can do the trick nicely. This works well for simple uses. It does, however, break references to an object’s class.

Suppose, for example, we want to reference the client object’s class with some new kind of greeting. And instead of the normal greeting, let’s make it say “Hi! I’m the esteemed Person, Jim.”

We don’t want to completely rewrite the method, so we’ll rely on super to get whatever is implemented in the regular Greeter.

class ProperGreeter < Greeter
  def name
    "the esteemed " + self.class.name + ", " + super
  end
end

proper_greeter = ProperGreeter.new(person)

proper_greeter.hello #=> "Hi! I'm the esteemed ProperGreeter, Jim."

Hmmm. That’s not what we expected. What we wanted to see was “the esteemed Person”.

This is a simple illustration of the fact that we have two objects and is an example of self-schizophrenia in Object-oriented design. Each object has its own identity and notion of self. We can fix that by changing the reference to use __getobj__ (the way SimpleDelegator expects) instead of self, but this is an illustration of how self does not refer to what we want. We must explicitly work with two objects and our mental model always requires that we think about two objects interacting when we only really care about altering the behavior of one.

This is not delegation. This is always two objects collaborating. Despite the numerous books, articles, and software libraries telling you otherwise. The Gang of Four got Delegation wrong, but that’s OK because now you know better.

Whatever, I’ll call it what I want

Who cares. Let’s not rock the boat. Everyone is doing it.

Yeah, Design Patterns showed examples in C++. And C++ can’t do delegation. So is that a valid argument for rewriting the meaning of a term?

If the language you use can’t provide it, don’t just call what the language can do “delegation.”

Get the concepts right

Developing an application requires that you understand not only your business domain concepts, but also understand many tools and approaches to your design. Software design patterns are common ways to solve common problems. Understanding what they are and when to use them is a key part of being an efficient developer.

The Design Patterns book is often lauded for giving names to commonly used software design patterns. This helps all of us use the same terms when discussing our software and prevents confusion.

Of course, as I began research for Clean Ruby I picked up the Design Patterns book for some clarity. “Surely this book will help guide the discussion and understanding of how to approach different patterns,” I thought. Sadly, it contains a glaring mistake that has been repeated and codified in numerous books, articles, and software libraries. Again and again I’ve read the same description of a behavior sharing and object composition pattern in software that is almost always given the wrong name.

The Design Patterns book is great for having pushed the idea of “composition over inheritance.” In fact, so many developers seem to love this phrase that you’ll probably be hit over the head with the term the next time you argue for setting up class-based inheritance. Thankfully, Sandi Metz defends class-based inheritance for its logical purposes in Practical Object Oriented Design in Ruby.

Design Patterns is often praised, not for innovation but, for its consolidation of terms. It guides us in the language that we use to understand and discuss different ways of approaching problems. It named for us common patterns so that we could better communicate with each other about what we are creating.

That praise, however, falls a little flat when you try to understand delegation.

My book, Clean Ruby, dives into understanding delegation and explores ways to keep your projects well origanized, maintainable, and loosly-coupled, giving you ways to share behavior and avoid cognitive overhead. Get it now and get your concepts straight.

Clean Up Your Code

If you liked this post and want more like it, get periodic tips in your inbox by leaving your email address below.

To get more information about cleaning up your objects, classes, and code, then check out Clean Ruby, an ebook which will describe ways to keep your code clean, maintainable, and focused on business value. Make your OOP more obvious, easier to understand, easier to test, and easier to maintain.



Comments

zaquest said on Tuesday, August 14, 2012:

I think that delegation is a transfer of authority (sharing behavior). No matter what way it was implemented (prototypical inheritance or method call forwarding) and what was context of execution. In fact, I think that delegated method is allowed to have different names on different objects, though usually it's not convenient.

Nik said on Wednesday, August 15, 2012:

That seems correct to me, propergreeter is calling a method. And what we want to see is that inside that method call, when there are other methods called, propregreeter's own methods take precedence, if propergreeter doesn't have those method, it should start looking up the chain.

So propergreeter does have a class method, which in turn does have a name method, then it proceeds to concat the name method of an instance of Greeter. that instance of greeter doesn't have name but that SimpleDelegator thing works such that Greeter is instructed to look for the name method in the person instance which is passed to it, as if Greeter was inherited from Person. when the 'name' method was found, it passes back to the 'name' less propergreeter and completes the 'hello' call.

So, you wanted "Hi, I'm the esteemed Person, Jim", saying that the #class#name method should have been evaluated in the context of Person, but isnt' that only true if the call, 'hello', is call ON an instance of Person? It is not. It was called on propergreeter, an instance of ProperGreeter. It actually would be strange if it was 'esteemd Person', because that implies that the further down the chain and away from the original things that makes the method call, the higher the priority of properties/method those further down objects have.

and as always, don't forget to reset the constructor of the prototype so to enjoy constructing new objects using existing instances instead of the original constructor function in JS ;)

Y_Less said on Wednesday, August 15, 2012:

Firstly zaquest has a point, why is implementation so important? Secondly, words evolve. If everyone who says "delegation" means the GOF version and the people they are talking to expect the GOF version, then that is the definition "by definition" (i.e. they mean that, so its what the word means). Words frequently change meaning in common use. If i said your article was "awful" you could be pedantic and assume I'm using the original meaning of "full of awe" (i.e. good), but that's probably not what it means…

Y_Less said on Wednesday, August 15, 2012:

To add to that, maybe the GOF did get it wrong, I'm not denying that, but that doesn't mean everyone else is getting it wrong. They are simply implicitly using the GOF definition rather than the original, and people know that.

foo said on Wednesday, August 15, 2012:

In C++, it is not possible (afaik, I am not aware of the latest language enhancements, but I'll be surprised if it did become possible) to do dynamic inheritance. However, the delegation principle you are describing is very simple to achive using virtual methods. The superclass must contain a virtual method for each method it wishes to access in its descendants, and descendants must override these methods to provide proper implementation, that's it. Of course, prototypal inheritance let you do have this behaviour through simple object composition (here I mean that you can build at runtime your final object using its prototype, which is imho the real value of composition).

foo said on Wednesday, August 15, 2012:

…but as I said above, C++ doesn't support prototypes.

Dan Midwood said on Wednesday, August 15, 2012:

This article should be retitled "The Gang of Four redefined delegation".

Naming design patterns gives us the ability to discuss such patterns without having to describe them. If the primary understanding of Delegation is GOF delegation then using the same term to refer to anything else will just cause communication problems and confusion.

It's difficult to see the original meaning of something subverted, but language changes and we need to accept that.

Sammy Larbi said on Wednesday, August 15, 2012:

Thanks for writing this up. It showed me a new way of thinking about delegation that I hadn't quite considered before: that the delegate can refer back to the delegator.

That's valuable.

However, I don't think it's worthwhile to argue about the definition now vs. the original definition. As others have pointed out, words change meaning over time. And as I mentioned to you on twitter: to me, words are about communicating, so we should use them in a way that furthers that goal.

In my opinion, arguing about a return to the original definition does not aid communication, because there is too much momentum to break.

You provided a learning experience for me though, which I greatly appreciate! Looking at it with this new knowledge, I think both cases can be called delegation, with the "original" adding some details I never considered (with regards to software).

Alexandre de Oliveira said on Wednesday, August 15, 2012:

Good to know. I always used the word delegate just like it's used in business administration, to let someone else do the job. Curiously, I always meant it passing self, specially after seeing Sandi Metz talks and her book.

The term forwarding, though, I have to start using it.

Personally, I think it's very important for everyone to speak the same language. Opposed to what some people think, naming is a very important discipline in the programming world.

Piers Cawley said on Wednesday, August 15, 2012:

In a language that doesn't do Prototypical inheritance, the workaround is to pass 'self' to the method you're delegating to. It's a kludge, but if it works for Smalltalk, it'll do for me. The trick is providing the method you're delegating to with enough information for it to do its job.

Doing it this way aids composibility as well, in that the object you're delegating to has fine grained control over when it needs to get state from the delegator and when it should get its own state.

In my own practice, I think of

def foo(*args)
    other_object.foo(*args)
end

as forwarding and

def bar(*args)
    other_object.foo_for(self, *args)
end

as delegating for pretty much the reasons you outline.

Piers Cawley said on Wednesday, August 15, 2012:

A much better book on patterns, especially patterns that translate well to Ruby, than the Gang of Four is Kent Beck's Smalltalk Best Practice Patterns. But you knew that already, right?

Don Hopkins said on Wednesday, August 15, 2012:

Two important things about Self that JavaScript completely misses:

1) Self objects can have MULTIPLE parent slots. JavaScript objects can only have one.

2) Self objects can change, add and remove their parent slots at runtime. JavaScript objects can only set their single parent slot at creation time, not afterwards.

Those are important, fundamental features of Self, that people usually sweep under the rug when comparing it to JavaScript.

dustin said on Wednesday, August 15, 2012:

To be a proper delegation example, by your own pull quote from Lieberman, questions "like what is the value of my x variable" have to be delegated back to the originally calling object. the calling object is definitely not "self", it's "get_obj". so the correct Ruby code gives true delegation, and you just haven't used it.

the keyword "self" isn't what's important, it's that Greeter has access to the Person object in the same way in each sub-class, which ProperGreeter does. then it can delegate the ".class.name" call to the proper object.

Flip Sasser said on Thursday, August 16, 2012:

Hey Jim! Great article.

I agree with you that the fundamental difference between passing messages to a new context and maintaining the delegator's context is worth keeping in mind when we use these terms.

Still, like other commenters, this makes me wonder if Henry Lieberman didn't use the wrong term? The English definition of "delegation" is not so different from what you call "forwarding." It seems like "teamwork" would have been a more appropriate phrase, as the objects in question share responsibility for accomplishing a task in which each brings a certain amount of knowledge to help the other.

Also, I can't help but feel that the real outcome here is to build your own delegation library that gets it "right" (healthy debate above about what's "right" notwithstanding).

It could so something cool like create anonymous subclasses that prioritize the message passing. Or something. I don't know; it would be a great crack at metaprogramming, I'll tell you that!

Mike said on Thursday, August 16, 2012:

"The Gang of Four have lead you astray." Should be 'led.'

Sebastian said on Friday, August 17, 2012:

For me the delegation definition of the GOF is completely logical, let someone else do the job. So forwarding and delegation are really the same thing. I don't think it is important what the original definition was, maybe that was wrong to start with.

It is important that we all have a shared understanding of the definitions, most people will understand delegation as defined by the GOF. And I believe it is better to keep it that way.

Ara T. Howard said on Friday, August 17, 2012:

delegation in ruby is simple

module Mixin def foo

bar + 2

end end

class C include Mixin

def bar

40

end end

p C.new.foo #=> 42

the article ends without detailing the simple answer nearly all good ruby libraries have been using since ruby 1.4 – it's just the java heads that build using the gof's tendency to make a class for absolutely everything

Piers Cawley said on Friday, August 17, 2012:

Sorry Ara, but you're missing the point. Including a mixin is essentially static thing that happens at 'compile' time.

The delegation that Jim's talking about is inherently dynamic, i.e., per instance. The object being delegated to can change at any time (down that road lies the State pattern) or it can be pretty much set in stone when an instance is created (which leads us to the Strategy Pattern, Chain of Responsibility and a bunch of others), or it can be fixed at compile time via either inheritance or by including a mixin, which is essentially inheritance by the back door.

itoctopus said on Saturday, August 18, 2012:

I wonder how many programmers actually used delegation in their code architecture.

I think that whatever the term really means, we don't really need it. It's really confusing and I've never been in a situation where I thought "Hey – this can only be solved by delegation".

Thanks for sharing!

Carl Anderson said on Saturday, August 18, 2012:

Interesting article. Reading the comments makes me think about delegation and inheritance in language even more. Not programming language, but English language. First we have the original use of the term in everyday language, and then if we think in Ruby: Person.new(:name => "Henry Lieberman"). His instance redefined the term in a specific way. Later, GoF redefined it again, and now we need to know which instance people are using on to know which definition is being referenced. I'm not sure why this struck me as so funny, but it seems to be relavant to the heart of the argument here.

Ryan Sandridge said on Sunday, August 19, 2012:

This is an interesting article, but I agree with others that you risk confusing vocabulary. GoF may have redefined it, but it is the common understanding. I fear if too much effort in correcting the terminology could lead annoying conversations that include a "Do you mean the original definition or the GoF definition?"

What isn't clear to me, which maybe we'll see in a follow up post, or in your book, is how the distinction is important. Case studies for when (original) delegation is the right tool, and case studies for when forwarding is the right tool.

But for now, thanks for informing me on a bit of nomenclature history.

Arlen said on Thursday, October 11, 2012:

This is typical of what happens when someone (in this case Lieberman) invents a new, completely technical, meaning for a common word.

Lieberman's (at least I think it's his, based on a skim of his paper and what you wrote here) insistence that you become me for practical intents and purposes while doing a task I delegate to you isn't in the original word (only the implication that you are acting with my authority). Which means someone else, who hasn't read his paper, wouldn't think that it was in that word. That's bad communication, something that a pattern language is supposed to short-circuit. (In defense of the GoF, though, they don't use it as a pattern, they merely use the word to describe a method of operation.)

Of course things change over time. Words acquire/retain their meanings by how they're used, not by the original intent of the coiner. I doubt Trigve Reenskaug would consider anything that passes for Model-View-Controller today to be similar to what he originally wrote about under that name, but so what? Neither he nor Lieberman gets to dictate language usage; the way english — even technical english — works is that anyone can propose a new meaning or usage for a word, but what really matters is how many other people you can convince to adopt the same meaning/usage, something the evidence readily available to hand indicates Lieberman failed to achieve. Still, that's not the major point, I think.

English is not a programming language. It describes things imprecisely. All things. "Delegation," the case in point, was used by the GoF to refer to a method of operation. If the language supports it directly, it would refer to that language feature. If it doesn't, it refers to whatever way you can use the language to achieve that end. For example, the javascript object.call() method is, by itself, a fairly correct implementation of temporary/dynamic delegation, AFAICT, as described here. So if the language at hand were javascript, I'd expect that or perhaps apply() would be part of what we were talking about. In ruby, though, we don't have that. SimpleDelegator gets you halfway, then adding in getobj gets you the rest of the way.

But what you write here does highlight another problem. It's nearly always suboptimal to name a library/language feature after a design pattern. It confounds communication — "when you say delegate, do you mean 'delegate' or do you mean the delegate.rb code?" I wish the ruby standard library hadn't done that. An exemplar for this practice is Avdi Grimm's DisplayCase, an implementation of a type of Presenter pattern.

Andrew Briening said on Wednesday, November 07, 2012:

Your example just highlights that the delegation library fails to undef the the "class" method.

Ruby doesn't support object prototype as a language feature. That means that Ruby's implementation of Delegation and Decoration will be with instance extension and method_missing ( probably on a BasicObject or the Delegation stdlib ).

You probably could devise something using ruby's "method" method and eval/instance_eval to attempt to make something more "prototype"-y. But why bother?

Here is something similar to your example in ruby that works:
https://gist.github.com/4032656

brutuscay said on Friday, January 25, 2013:

Delegation in Ruby is made using DelegateClass(SomeClass)
http://www.ruby-doc.org/stdlib-1.9.3/libdoc/delegate/rdoc/Object.html

1999 - 2014 © Saturn Flyer LLC 2321 S. Buchanan St. Arlington, VA 22206

Call Jim Gay at 571 403 0338