Gene Michael Stover was reading about design patterns & thought that the Visitor design pattern dissolves into a non-issue in CLOS, but that seems too good to be true. Could someone check my reasoning & back it up or tell me where I went wrong?
The purpose of the Visitor design pattern is to allow new operations to be added to a class hierarchy without recompiling the class hierarchy.
The Design Patterns book & also Modern C++ Design (by Alexandrescu) implement the Visitor D.P. for C++. They add an Accept method to each class in the main hierarchy. The Accept methods call the appropriate method on a Visitor object.
To me (Gene Michael Stover), it looks like the Visitor design pattern simplifies hugely in Lisp/CLOS.
You can get a half-hearted simplification because CLOS methods can dispatch on more than one object, so you don't need to add an Accept method to the hierarchy that you don't want to alter but that you want to add the operation to. Here's an example:
(defclass Apple ...) ; a concrete class (defclass Banana ...) ; ditto (defclass Orange ...) ; guess what (defclass Fruit-Basket ...) ; concrete container of fruit ;; Here's how we can create a Visitor object to sum the ;; calories in the other objects, but without adding any ;; methods to the other classes. (In the C++ implementations, ;; the other classes would need Accept methods.) (defclass calorie-counting-visitor ...) (defmethod visit ((vis calorie-counting-visitor) (app apple) ; count & return the calories in the ; apple ) (defmethod visit ((vis calorie-counting-visitor) (ban banana)) ...) (defmethod visit ((vis calorie-counting-visitor) (ora orange)) (defmethod visit ((vis calorie-counting-visitor) (fb fruit-basket)) (loop for fruit in fb (accumulate (visit vis fruit)))
I think the example is correct. It mimicks the Visitor design pattern implementations for C++ except that there is no need for an Accept method on the concrete classes. But because the purpose of the Visitor design pattern is to add operations to classes in a hierarchy without changing (& recompiling) that hierarchy, I think a further simplification is possible via CLOS's multi-dispatch feature. You don't even need the CalorieCountingVisitor class at all. Here is an exmple:
Assume the Apple, Banana, Orange, & Fruit-Basket classes are defined elsewhere, & you want to add calorie-counting functionality without alterning those classes. No sweat! In another file, create a Count-Calories generic & methods, like this:
(defgeneric count-calories (x) ...) (defmethod count-calories ((self apple)) ...) (defmethod count-calories ((self orange)) ...) (defmethod count-calories ((self banana)) ...) (defmethod count-calories ((self fruit-basket) (loop for x in self (accumulate (count-calories x))))
It looks like CLOS makes the Visitor design pattern superfluous or a non-issue. Certainly the implementation of Visitor does not require the complex code in the Modern C++ Design book.
It sounds too good to be true. Can someone verify or refute what I've written? (Gene Michael Stover. Go ahead & remove my pseudo-signatures if you see fit after the question is answered.)
You are exactly correct. This is one of those things that finally convinced me that typical OO models are far too limiting; CLOS's decoupling of methods and objects, and the availability of multimethods, is the right way to do things. (I am thoroughly sick and tired of maintaining all the visitor classes in my C++ relational algebra library at work.) If you hunt around on the net a bit, for instance at the C2 wiki, you'll find discussions regarding the fact that many of the Gang of Four OO patterns are just not at all relevant to Lisp, because they're too trivial to warrant a pattern when implemented with CLOS.
But wait, there's more. Paul Graham said ``Peter Norvig found that 16 of the 23 patterns in Design Patterns were "invisible or simpler" in Lisp.'' See http://www.norvig.com/design-patterns/
Gene Michael Stover's comments about Visitor can be found at http://www.lisp-p.org/controversy/
They include a pointer to "Design Patterns Considered Harmful" by Dave Smith at http://perlmonks.thepen.com/133399.html