"I have a mind like a steel... uh... thingy." Patrick Logan's weblog.

Search This Blog

Sunday, August 21, 2011

Double Dispatch In Objective-J

My previous post describes a controller for separating an application's model from Cappuccino's CPOutlineView. But there's actually one place where the model and view kind of meet up:

- (id)outlineView:(CPOutlineView)outlineView objectValueForTableColumn:(CPTableColumn)tableColumn byItem:(id)item
{
  return (nil == item) ? @"" : [item objectValueForOutlineColumn: tableColumn];
}

I decided to have the controller give a model class access to a column, which is part of the view. Why?

This example has four kinds of columns and three kinds of model classes. Each column wants to display each kind of model element differently. One obvious solution is to use a conditional expression:

if the column is a ... and the model element is a ... then ...

But even simple object-oriented languages like Objective-J have easy mechanisms and patterns for reducing the need to test objects for their class or whether they implement some specific message. Going way back in Smalltalk lore, there's Double Dispatch.

The goal is to reveal to a column the presentation object to use in each of its rows. To do so, the column view, CPTableColumn, is subclassed for each kind of column in the example's outline:

  • SDNavigationColumn
  • SDTopicColumn
  • SDNotesColumn
  • SDDateColumn

Each of these subclasses implements the following methods:

  • objectValueForTopLevel:
  • objectValueForPriority:
  • objectValueForStuff:

Each of the model classes implements objectValueForOutlineColumn: by sending one of the above messages to the given column. For example, SDStuff is implemented as follows:

- (id)objectValueForOutlineColumn:(id)anOutlineColumn
{
  return [anOutlineColumn objectValueForStuff: self]; 
}

This dispatches right back ("double dispatch") to have the column respond with the awareness that it is on a row for detailed stuff. Each column will be interested in different aspects of the stuff. The navigation column is only interested in hierarchy and not details. Here is its implementation, which just returns the empty string to indicate its disinterest:

- (id)objectValueForStuff:(SDStuff)aStuff
{
  return "";
}

On the other hand the date column is interested in a presentation of the given date:

- (id)objectValueForStuff:(SDStuff)aStuff
{
  return [[[aStuff date] description] substringToIndex: 10];
}

Although this kind of brings the model and the view together, the names could be refactored because there is nothing really "column-specific" about this mini-protocol. Also Objective-J has "categories" for grouping methods. The intent of this protocol could be explained by placing the methods in a "presenting" category.

There are certainly more elaborate mechanisms available for keeping views and models separated, yet in-sync. Double Dispatch is just a simple one for reducing the need to test for classes and messages before sending them.

No comments:

Blog Archive

About Me

Portland, Oregon, United States
I'm usually writing from my favorite location on the planet, the pacific northwest of the u.s. I write for myself only and unless otherwise specified my posts here should not be taken as representing an official position of my employer. Contact me at my gee mail account, username patrickdlogan.