4

Is the visitor pattern useful in languages supporting class extensions?

Why bother implementing it, when you have open classes or can subclass. If you want new functionality for a class you could just subclass it, so unless I'm missing something, is it still (very) useful in languages supporting class extensions?

  • 1
    Who said the visitor pattern is useful in languages not supporting class extensions? ;P To me the visitor pattern (and many others) lose all usefulness completely when a language get's higher order functions. The abstractions that feature gives you makes most design patterns look downright klunky; including the visitor pattern. – Jimmy Hoffa Jan 17 '14 at 19:40
3

The visitor pattern often uses the double dispatch pattern. So for me the visitor pattern is

double dispatch + structure traversal.

You will need the structure traversal even if you have refinements or subject orientation. But the double dispatch may take on other forms.

  • 2
    GoF book says nothing about traversal. The fact is, most uses of Visitor pattern are traversals (including my example of Pharo's AST-Core). – herby Jan 17 '14 at 23:25
3

Though as you write it is not technically needed to implement the double-dispatch functionality, it is still used. For example in Pharo Smalltalk (Smalltalk has class extension, they are easy to do, and you can package them easily with *Package method category) 3.0 visitor pattern is used - see AST-Core package.

The reason for this is organizational - a visitor encapsulates "ways how to handle these cases" and for the human apprehending the code it may be valuable to have it at one place, with familiar names.

If there would be user-friendly AST-based pivotable multidimensional (insert-your-own-buzzword) code browsers/editors, there would be no need for Visitor patterns per se in these languages. But we still browse the code in chunks like packages / classes.

1

The visitor pattern isn't meant to extend the functionality of some class. It is a pattern that provides an elegant way to operate on some data (e.g. to traverse it) while the visitor can keep state and handle different types of data differently.

For example consider a pseudo-DOM where we want to collect all headlines, in a language with type-overloaded methods:

class CollectHeadlinesVisitor {
  List<String> headlines = new List<>();

  public void visit(Node n) {
    for (Node child in n.childs()) {
      this.visit(child);
    }
  }

  public void visit(Headline h) {
    list.add(h.text());

    for (Node child in n.childs()) {
      this.visit(child);
    }
  }

  public List<String> value() {
    return headlines;
  }
}

Note that in a language without type overloads we have to do the accept/visit_Type indirection.

The above example can't be implemented by adding methods to Node and Headline as a place is needed to store the discovered headlines.

Adding methods to the existing data classes would also violate the Single Responsibility Principle and could lead to namespace issues, e.g. when two pieces of code both monkey-patch some visitor methods. Some languages do solve this, but this doesn't mean that it's recommendable. Subclassing is not an option as we want to be able to perform new behavior on existing data.

Using pattern matching as in ML-derived languages isn't an option either, as this isn't extensible (in my example, I could subclass the visitor to handle another node specially as well).

  • 1
    you are missing one of the key points of the Visitor pattern, the visitor is not supposed to know how to traverse the object, this would require knowledge of the inner structure of the object. The object is supposed to accept a visitor and traverse it's own internal structure. – crad Jan 17 '14 at 23:55
  • @crad Yes, however that runs counter to my argument. A Visitor is already tightly coupled with the type of data it operates on, so knowing how to traverse that data could be expected. Using the accept for a level of indirection can be difficult to do in a truly general way when using a too static language. It also requires us to add functionality to existing classes, which the Visitor pattern otherwise avoids. There are different variations of this pattern, use that which fits the problem. – amon Jan 18 '14 at 8:43
-2

If you ever have to write a compiler you will need to use visitor pattern. The number of subclass cases you would have to handle without it would make any other method prohibitive, or at least horribly unenjoyable.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.