1

From what I understand, the visitor pattern is supposed to solve the expression problem (described here), where a program needs to support performing multiple operations on multiple types, ideally allowing adding new operations and new types without touching existing code.

  • OOP languages can define a method for each operation on each type of object; this makes it easy to add new objects without modifying existing code, but adding a new operation requires modifying all existing objects.
  • FP languages with pattern matching have the opposite issue; adding a new operation is self-contained, but adding a new data type requires modifying all existing functions to support the new type.

The visitor pattern, as I understand it, just changes the OOP style to the FP style; adding a new operation just means adding a new type of visitor, but adding a new data type means adding a method to all existing visitors. Is my understanding correct? If so, what's the benefit of the visitor pattern, if it doesn't fully solve the expression problem?

6

I'm not sure that the visitor solves the "expression problem". But your understanding is correct:

  • You can derive new visitors based on the abstract visitor. This allows to define new operations that will work on all visited elements.
  • But if you add to the visited's object structure an element of a new type, you'll need to update the abstract visitor and all its concrete derivations in order to add a member function for coping with the new type of elements.

The visitor is designed to perform an operation on a complex structure with substructures (typically on a tree-like composite), and allow to add new operations without changing the visited classes.

Not related: I would be careful in opposing OOP and FP. You have FP languages that allow their functions to get immutable objects as input and produce objects as result, and you have OOP languages that have introduced FP features, allowing to implement FP logic if the programmer wants to).

| improve this answer | |
  • Thanks; good to know I have the right idea. I guess the main benefit is just that it allows that tradeoff, if you're constrained to working in an OOP language? – DylanSp Jan 9 at 21:09
  • 1
    And yeah, OOP vs. FP is an oversimplification, but it's easier to say than "language with subtypes and inheritance" vs. "language with algebraic data types and pattern matching", which are the features that matter here. – DylanSp Jan 9 at 21:10
  • @DylanSp I understand the simplification. I just wanted to draw the attention that the simplification might end in unproductive flamewars that do not help to advance software engineering ;-) I think the visitor is a very specialised pattern that only has advantage for some very specialized cases and for very complex structures. In many cases, you can opt for iterators and use a map-reduce style (see algorithm, numeric and iterator libraries of C++ that are heavily used in conjunction with lambda functions). Out of curiosity, how would you categorize Ocaml ? – Christophe Jan 9 at 23:20
  • @Christophe After going through GoF book or wikipedia, it seemed to me that, for a language such as Java, visit/accept were unnecessary (A prettyprint class could simply traverse an ASN tree and print (referring to GoF example)), unless the traversal itself was nontrivial and was subject to change. Is that what you mean in above comment? – Chethan Jun 7 at 18:07
  • 1
    @Chethan indeed I was not sure it’s the visitor is the best way for this kind of problems, especially if you add new types. An interpreter pattern seems more appropriate for run-time defined expressions, and an ASN tree traversal likewise. But as it is, the problem is too general to recommend a best approach. – Christophe Jun 7 at 23:11

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.