Regarding additivity discussed in this chapter:

This is the well-known expression problem.

<< Previous exercise (2.75) | Index | Next exercise (2.77) >>


Data-directed style is the most appropriate when new types must often be added.

Message-passing style is the most appropriate when new operations must often be added.

brave one

Actually I don't see the difference: in both cases we have type as a unit, which contains operations. Just dispatch in data-driven variant is external and in message-passing internal. So types are easy to add always, new unit doesn't touch old stuff. And operations touch everything.


Hmmm, people seem to be forgetting that there are three strategies here, not just two:

For generic operations with explicit dispatch (which is the same as the "functional programming approach" described in the wiki link above), adding new operations is easy (i.e. can be done without changing existing code).

For message passing, adding new types can be done without changing existing code, but adding new operations requires changing all the old code.

Data directed programming actually "solves" the Expression problem by allowing new types *and* new operations to be added without changing existing code: To add a new type I just fill out a new column in the table of operations, to add a new operation I fill out a new row. (Note that style used in the book of putting all the operations for e.g. the rectangular representation together makes it seem like adding a new operation to all the representations would be hard, but there's nothing stopping me from having my own define block where I register a 'complex-conjuage method under 'rectangular and 'polar.)

Of course, the amount of code that needs to be written to add a new type or operation is about the same under all three approaches - the only difference is how spread out that code needs to be, and how easy it is to locate all the places where code needs to be changed. Data directed programming seems to optimize for the former at the expense of the latter.


I found torinmr answer to be correct one. What brave one I think is missing is that in data-directed approach one doesn't necessarily need to modify existing install-package declaration to add new operations. It can be done in newly written install-package block or just by registering new operations with series of put calls: either for new type or in the case we want to add operation for all of the types.


I think Brian Harvey said it best in his 2011 Berkeley course on the topic, when he stated that "old code should not stop working when you add new code".

In this case: