Talk:Visitor pattern

Page contents not supported in other languages.
From Wikipedia, the free encyclopedia

codeproject.com link removal[edit]

I propose to remove codeproject.com from the Other links. It has 110 links on Wikipedia raising the issues of advertising, promotion, spamming, and just plain over-linking. Comments anyone?

--C# Online.NET Editor 14:51, 12 February 2007 (UTC)


I am adding problem statement to understand the design usability better.

In organization there are different kind of employees and consultants so you can make a hierarchies based upon employee profile. Like Payee->Employee-> Management, Worker, Engineer. Payee->Consultant->Management, Engineer. Each have its own salary and salary-structures and saving/saving-plans. We have some algorithms to calculate deduction from pay for each one. Now a software need to design to calculate different deductions from pay of different profile's payees. These algorithms can be in different class and those classes will be visitor class. And the software can follow the Visitor Design pattern for best design. --Akash Gupta --203.90.124.178 11:59, 22 Jun 2004 (UTC)

With regard to the above, the Visitor Pattern would be useful if you have an aggregate object representing the organization chart, and you want to traverse that chart, applying an algorithm to each element of the chart such that it's customized to the type of that element. The chart's accept() function provides a way to map through the chart, it's a function applicator. The visitor is the function to be applied to all parts of the chart.

If you have some conventional list of the employees, you don't need the accept() thing; you use some existing list iteration mechanism to "visit" all of these objects. Moreover, perhaps there is no need to split the algorithm away from the objects. You can perhaps just put the payment deduction into a function in the Employee class that can be overridden. Or, an Employee object can have a helper object that handles details of payroll.

for_each (employee in employee_list) {
  PayrollPolicy *policy = employee->getPayrollPolicy();
  policy->CalculateDeduction(employee);
}

Smalltalk single dispatch?[edit]

The 3rd paragraph states this: "... in a conventional single-dispatch object-oriented language such as Java , Smalltalk, and C++."

I'm not directly familiar with Smalltalk, but I've always thought that Smalltalk used double-dispatch.

Can anyone confirm that?


Well, I think I'd also heard that, but a simple look at Smalltalk shows it's not allowed by the sintax: You write an object (or an expression returning an object) and then a message to send to it ("method to invocate on it")... And define methods writing "Class>>Message: Argument[s]"... So unless something is ommited in the article, there's no way to define double-dispatch methods.
(Well, it's the first time I look at SmallTalk, so perhaps I'm wrong =) )
-- User:E-uyyn

Some poorness[edit]

Until we include in the article explicitly what problems this construct addresses, it will remain poor. I'm a not-very-stupid 5th degree Computer Science student and had to deduce by myself this pattern's utility: So I imagine the article will be worthless for the main reader.

I agree with this assessment. Once the usefulness finally occurred to me (no reflection needed to handle different types), I went to the Java and C# example and expected to see the VisitorDemo iterating over a bunch of objects of indeterminate type and not having to use reflection. Instead, VisitorDemo just creates a Car object. The Visitor pattern isn't even useful in this scenario. Can we please get some better examples, and some better code samples? ThePedanticPrick 15:53, 12 April 2006 (UTC)[reply]
Ok, wait, I get it now. Car.accept passes the visitor to the accept methods of its components. I should have read more carefully. Nevertheless, this highlights the need for more clarity on the page. Also, it seems like there's more than one benefit to using this. There's the simulation of double dispatch, or what I called "no reflection needed", there's the ability to let an object handle its own component composition (also something we need to explain more clearly), and what BenFrantzDale describes below, the ability to decouple the function from the objects. He also goes on to describe something I don't fully understand yet, not being a graphics guy. ThePedanticPrick 19:27, 12 April 2006 (UTC)[reply]
Two useful examples would be scene graphs and abstract syntax trees. Both often make use of the visitor pattern to traverse them. I think the Car example is good though, since it is pretty simple, but still illustrates its purpose. It is a complicated pattern, and its utility can be hard to see, but, trust me, once you need it, you'll get it right away. —Preceding unsigned comment added by 216.8.167.246 (talk) 20:20, 18 February 2009 (UTC)[reply]

Yes, please please please come up with a better example -- show the pattern saving you work and making things clearer, not multiplying the amount of code by 10x and making things harder to understand. The collection should be something that's a pain in the butt to traverse, like an incoming XML stream to be SAX-parsed. Another way to highlight the advantages of the pattern is to offer different traverses to the same visitor class(es), e.g. allow the client to apply an XPath filter to that XML traverse. -- 38.105.178.219 (talk) 06:10, 15 October 2009 (UTC)[reply]

As far as I understand:

The pattern addresses the application of a function object (≈closure for lispers) to each component of a composite object. Specifficaly, it is valuable when you are using multiple different functions this way in the same classes. The pattern effectively separates the code used to navigate through the composite object's structure (thus, dependant on the structure) from the code which may be applied to each component.

In the ""regular/easy way""? (I mean, without using this pattern... anybody has a better wording for that?), the navigation code would be included, redundantly, in the different function objects, maybe even intertwined with the "apllication code".

As always, the problem with code redundancy is not the repetition itself (((the code-replication problem was solved long ago by the mighty programming utils copy and paste, not to menction lisp macros ;) ))), but redundancy in code which is dependant on a decission, such as the composite objects' structure in this case. The problem arises when the decission (i.e., the structure of the object) changes: The same corrections would have to be made, again and again (because of the redundancy), across several functions in the code. This wastes programmers' time, which is very expensive, and is error-prone (as is every task requiring a human to do a search).

If redundant code isn't factored-out, the time expended in corrections would be completely lost should a new change in the decission be made.

As an additional benefit, the pattern not only eliminates the said redundancy, but also puts the navigation code in the composite class. It is desirable to have dependent code in the same module (class for O.O. languages) in which the decission they depend on is taken (in this case, the decission is the class structure, which is specified in the class declaration/definition), so it can be inmediately fetched if a change needs to be done.


Remarks, please? -- Euyyn

The use described in Design Patterns is to move a higherarchy of methods into one place so that adding more such methods doesn't get out of hand. For example, if you have objects that will be drawn on the screen, you could have a draw() method for each. However, if you wanted to then draw them to an OpenGL context, you would have to add draw_OpenGL() methods. Then if you wanted to draw to postscript, you'd add draw_PostScript(). Each of these additions would scatter platform-dependant drawing code across all the files of the class higherarchy. If you use the visitor pattern, you'd be adding a single class for each of these additions and that class would contain all of the platform-dependant code.
Furthermore, if you have objects in scenegraph, you might want to draw them in different orders depending on the nature of the drawing context. For example, in OpenGL you might want to draw all brick-textured objects together to avoid excess context switching. The OpenGL visitor could collect a list of things to draw, sorted by texture usage, and only then would you draw the scene. This could not be accomplished easily with a simple recursive draw() method. —BenFrantzDale 20:25, 28 November 2005 (UTC)[reply]

This article is the #1 Google result for "visitor design pattern" and "visitor pattern". It needs to get better. There's lots of vague language and the organization seems poor. Also as other people have noted, the code examples are not very illuminating. Gandalfgeek (talk) 23:12, 3 July 2008 (UTC) gandalfgeek[reply]


Some comments

Here are some things that might be of interest:

  • The biggest drawback of the Visitor Pattern seems to be that each visitor needs knowledge about every single Element implementation class. This becomes obvious when the Visitor implementation is compiled into a library but a user of this library has the ability to derive new element classes.
  • A Visitor might (or might not) contain a default implementation of visit(Element) for implementations not handled by special methods. The simplest Visitor implementation would thus just contain a single visit(Element) method that performs an action applicable to any implementation. In this scenario only the navigation through the hierarchy is factored out but concrete actions remain as methods in implementation classes (MyShape.draw() vs. MyShape.draw_OpenGL()).
  • In more complex scenarios, these actions may be moved into the visitor. MyShape.draw() is replaced by DrawVisitor.visit(MyShape), MyShape.draw_OpenGL() is replaced by OpenGLDrawVisitor.visit(MyShape).
  • A full-fledged Visitor implementation would contain two callback methods for every concrete implementation class, because some actions might have to be taken before aggregate elements are visited and some after. The accept() methods in concrete Elements would then do visitor.startVisit(this); call accept(visitor) on each aggregate element; visitor.endVisit(this). —Preceding unsigned comment added by 78.54.7.83 (talk) 10:45, 19 July 2008 (UTC)[reply]

Poor sample If a reader looks at the Java example, he/she might ask: what do we need the double-dispatch for here? And actually double-dispatch is only needed if there would be inheritance in the class hierarchy or at least the iteration of the subobjects is performed in the classes themself, not the visitor. So in effect, the example is very poor. —Preceding unsigned comment added by 195.243.100.246 (talk) 14:39, 18 June 2009 (UTC)[reply]

UML[edit]

I've created and added a UML diagram to the article. Let me know if its semi-decent. I come from a Java/C++ background, so I don't know if the diagram applies to the other languages as ubiquitously as I've assumed. I also tried uploading the original .dia file so the image my be edited easily if needed, but it complained that it wasn't a recommended image format :-/ If you want it, just drop me a line. It's not rocket-science, but it does take some time to do all that clicking. The Extremist 10:08, 9 December 2005 (UTC)[reply]

please post it here so that we can discuss it :-) MatthieuWiki 17:26, 13 July 2007 (UTC)[reply]

Examples[edit]

These examples have gotten out of hand. There need only be one example of this; more than one adds nothing about the pattern itself. I propose it get cut back to just one of the Java, C++, Python, or C# example, and the rest get moved to Wikibooks. Thoughts? —Ben FrantzDale 03:16, 22 May 2006 (UTC)[reply]

Where is it?

I'm not sure who wrote the previous paragraph ("Where is it?"), and at first I wasn't even sure what it meant, but now I understand: There used to be more examples and now some are gone, allegedly because only Java is needed. But if the others were moved, to where were they moved? I join in asking that question. There is a broken (i.e., red) link to visitor pattern examples. Also, there's more than Java there now: there's C++, either because it was not removed or because it has crept back in. If there are going to be multiple languages, let's please restore the Lisp, too. If there aren't, and it's because everyone can read Java, then what is C++ needed for? Although I don't especially like Java, I can live with it as the exemplar if the justification is that there should be only one language and that the first example offered was in that language. Recall that, like it or not, this is more than just documentation: the presence of extra languages here becomes a de facto advertisement for the "preferred" languages and invites every language in the universe to offer its version once a pattern has been shown (sorry for the bad pun). It would seem best not to start down that path. Netsettler (talk) 02:23, 28 March 2008 (UTC)[reply]

Examples should show a single implementation from various classes of languages. E.g. the Java and C++ examples show really the same thing, modulo some syntax, which is not surprising as they are both statically typed OO languages. There should also be an example from a dynamic language like Python, Ruby, or Javascript, as well as a discussion of how the pattern implementation is significantly different in dynamic languages due to the use of reflection (e.g. the compiler.ast module in Python 2.5 has an idiomatic implementation of the visitor pattern). —Preceding unsigned comment added by Gandalfgeek (talkcontribs) 04:53, 29 June 2008 (UTC)[reply]

These examples are still out of hand. I still think Java is the best example language for this since it is strongly typed and has garbage collection so all of the pertinent details are explicit and all of the nuisance things (memory allocation) aren't needed. (FWIW, I'm not a fan of Java; I barely know Java and like C++ and Python.) If it weren't for the fact that strong typing goes well with OO design patterns, I'd go for Python for its similarity to pseudocode, but I think things would be lost for this example without typed arguments and without proper abstract base class. At the risk of re-starting an edit war, I'm going to be bold. —Ben FrantzDale (talk) 00:55, 8 April 2009 (UTC)[reply]

The Lisp example is just using multiple dispatch and is not an example of a visitor pattern at all. This is confusing and I'm deleting it. The visitor pattern exists to get around the limitations of single dispatch languages, so an example in a multiple dispatch language such as Lisp is only going to confuse and mislead people. tjwoods (talk) 20:29, 6 February 2013 (UTC)[reply]

Hmmm, I guess reading all the way through is a good thing. I just read the part of the Notes after the Lisp example that reads ...all traces of the Visitor Pattern disappear..., so I guess it is providing a useful contrast with the visitor pattern. However, I still think the presentation is confusing. Perhaps the Lisp example should be in a section such as Visitor Pattern vs. Multiple Dispatch, since these are two solutions to the same problem. tjwoods (talk) 20:41, 6 February 2013 (UTC)[reply]

How about a more realistic example...?[edit]

These car examples are all well and good, but fail to recognize any of the difficulties that instantly come up when traversing, say, source code or object code. I've done this several times now and the visitor pattern just doesn't seem to be reducing overhead for me - it still needs to be essentially re-written for each use, and in general causes about as many problems as it solves. I'd be interested in other people's thoughts... Dan Knapp 16:47, 24 May 2006 (UTC)[reply]

You might want to take a look at "Visitor Combination and Traversal Control" by Joost Visser - it specifically addresses visitor reuse and traversal strategies. 129.34.20.19 14:22, 29 June 2006 (UTC)[reply]
The key is that it gives you double dispatch. This essentially allows you to add virtual methods to classes that already exist. As a result, you get the power of virtual methods without having to add bloat to the classes. Plus it localizes a particular algorithm to one class rather than scattering it across classes.
For example, suppose I have a scenegraph with heterogenious objects that I want to draw. One way to draw this would be to have each object inherit some drawable class and implement draw(). But now suppose want to draw it to both OpenGL and DirectX. I'd probably put in a draw_OpenGL() and a draw_DirectX() method. This wouldn't scale well to more drawing modes, would spread platform-specific code across all drawable objects, and would put drawing code in classes which fundamentally represent drawable things, not ways to draw them. (That is, a cube is a cube even if it doesn't know anything about OpenGL.)
In contrast, using the visitor pattern the OpenGL drawing functions would all be in one file, the DirectX functions in another file, and adding another drawing mode would simply be a matter of adding a third file.
Does that help? —Ben FrantzDale 22:25, 27 July 2006 (UTC)[reply]
Yes, that tells me a lot more about what one is supposed to gain from the pattern. I'm used to languages that have multimethods anyway, which was part of why I didn't get it.
I do feel compelled to point out that realistically, it's unlikely one would want a third 3D API, but the separation you describe is definitely a good thing.
Thanks. Dan Knapp 03:50, 8 November 2006 (UTC)[reply]

A simple example that I recently implemented involved parsing wikicode. Once the wikicode had been parsed into various elements like WikiText, WikiLink etc, Visitors can be coded to output to different formats, e.g. html or plaintext.

class HTMLVisitor
{
  public function visit(WikiLink $l)
  {
    echo "<a href=\"" . htmlentities($l->url()) . "\">" . $l->text() . "</a>";
  }
  // ...
}
class PlainTextVisitor
{
  public function visit(WikiLink $l)
  {
    echo $l->text() . " [" . $l->url() . "]";
  }
  // ...
}

I think the visitor pattern works well for translating an intermediate format into some external format. This is why compilers use visitors to generate machine instructions for different architectures.84.66.221.139 23:23, 11 December 2006 (UTC)[reply]

Can any one add the compiler example as it is coming in discussion so many times. For the end user it is good to know the very basic implementation of this pattern. or any link to it would be great. —Preceding unsigned comment added by 203.91.193.7 (talk) 10:01, 30 March 2009 (UTC)[reply]

Multimethod[edit]

Multimethod is a more general term for "double dispatch".

Err... no. Double dispatch means you do a double-hop from a visited class back to the visitor, thereby avoiding the issue with having to perform visiting in the classes themselves. On the other hand, multimethods imply multiple dispatch where the invocation depends on the argument type in a polymorphic manner. See the C# example with dynamic dispatch for an implementation.

Car class in example is wrong?[edit]

As I understand the visitor pattern, shouldn't the the Accept method of the Car class call Accept on the Body, Engine, and all the wheels? —The preceding unsigned comment was added by 217.166.1.202 (talk) 10:20, 26 February 2007 (UTC).[reply]

I agree with the above comment. The responsibility of a visitable object is to provide navigation to sub-components. A visitor would only be interested in adding extended functionality to individual nodes and should not be aware of how the nodes are linked. This is the responsibility of the aggregated object itself. --Pav007 11:53, 14 March 2007 (UTC)[reply]
I don't have Patterns in front of me, but I believe it can go either way. —Ben FrantzDale 12:05, 14 March 2007 (UTC)[reply]
It does seem to contradict the article though, which says: "In the simplest version, where each algorithm needs to iterate in the same way, the accept() method of a container element, in addition to calling back the visit() method of the visitor, also passes the visitor object to the accept() method of all its constituent child elements". Now, this implies that things can be different (needs clarification, by the way), but one would hope that the example should demonstrate the "simplest version" anyway. So i'm going ahead and fixing it. -- int19h 17:24, 15 March 2007 (UTC)[reply]
The article also says that: "the visitor design pattern is a way of separating an algorithm from an object structure upon which it operates". So, according to this, visitor is the algorithm (operations), and the car is the structure upon which it operates. The point is that algorithm (the visitor) should not know about the structure. Thus, the car should define its structure for the algorithm, and the initial call visitor.visitCar(car) should be replaced with car.accept(visitor), where car should call accept(visitor) for each its element. —Preceding unsigned comment added by 77.123.143.133 (talk) 07:20, 26 November 2008 (UTC)[reply]
It is true that the visitor pattern can be interpreted in both of these ways (I prefer a visitable Car which calls accept on its parts). But implementing the traversal in each of the Visitors is a clear violation of the DRY principle. If the car stays not beeing visitable, there should at least be an ordinary function (not member) VisitCar which implements the traversal. —Preceding unsigned comment added by 93.190.250.146 (talk) 07:58, 22 July 2009 (UTC)[reply]
As it stands, the Visitor pattern is one of the least undertood and Wikipedia should serve as a reference in this respect. If there are differing views they should be presented. Some sources do state that this pattern should be used to add an operation without changing the elements it operates on. --JamesPoulson (talk) 20:18, 15 August 2011 (UTC)[reply]
Update: This Javaworld article describes a more flexible approach to using this pattern. It would be impratical to modify standard classes such as String so what is done is to wrap the target class inside another which implements Visitable/accept interface. This avoids having to modify an element. --JamesPoulson (talk) 22:17, 15 August 2011 (UTC)[reply]

Duplicate examples in different languages[edit]

Given that the D example adds nothing that the Java one doesn't, I'm removing it. All it does is illustrate the D language, which isn't the point of this particular article. Matthew0028 02:58, 19 June 2007 (UTC)[reply]

C++ example is badly coded[edit]

In my opinion the c++ code example needs to be rewritten or removed. Some issues: There's member variables in the public interface, the classes are guaranteed to leak since there's no destructors and no way to obtain pointers to the dynamically allocated memory. The Microsoft-specific "stdafx.h" precompiled header file is included. Const-correctness is not exercised. std::string objects are passed by value. A temporary iterator is stored as a member. "using namespace std;" is placed is one of the header files. I have put up a cleanup template for now. Ufretin 15:17, 3 October 2007 (UTC)[reply]

I agree, I think the C++ example is awful and must be rewritten exactly to cover some scenario where a Visitor actually makes sense. See the C# section for a corresponding example. Dnesteruk 18:49, 25 April 2016 (UTC) — Preceding unsigned comment added by 109.151.222.203 (talk) [reply]

Callback[edit]

It seems like there should be some mention of callback, http://en.wikipedia.org/wiki/Callback_%28computer_science%29, or just a link to it somewhere within this article.

Unencyclopedic language[edit]

I'm not sure if expressions like "If I have a bunch of classes" are very encyclopedic. Also things like "The idea is to" is something you might see in a newsgroup post or an informal publication, not in an encyclopedia. Wopr (talk) 14:46, 9 March 2008 (UTC)[reply]

Similar concept?[edit]

please fixme if i am wrong. i was thinking about it and i realized that this "visitor" thing can mean "unification". color_t blue, red, green; // initialize somewhere draw_dot(red); // each color is different "object"

// versus enum color_e { BLUE, RED, GREEN, NUM_COLORS }; color_t color[NUM_COLORS]; draw_dot(color[RED]); // colors are accesed as one *color this example shows that colors are unified. but visitor is more about hoisting up same behaviour, which changes with given context. i'd like to have it clear. Xchmelmilos (talk) 18:27, 11 March 2008 (UTC)[reply]

Example doesn't match narrative[edit]

The narrative indicates that the Car class would call the visitor on itself, and then on each of its elements (thus the visitor need not know the structure of the Car class). The example as coded does not reflect this structure, thus providing a misleading example. I can correct this, but will first just serve notice and let the original example provider correct the code if he/she is so inclined. NedHorvath 06:42, 20 September 2008 (UTC)[reply]

NULL vs 0[edit]

Prefer NULL over 0, because:

The C++ standard doesn't guarantees that a null pointer is equal to 0. Using 0 would make you code not fully portable. Since NULL is a macro you could (re)define it ones, rater than having to edit you code in many many places.

You are completely confused. The use of 0 as a null pointer is C and C++ is completely portable, regardless of the internal representation of an actual null pointer. When used as a pointer, 0 is BY DEFINITION a null pointer. Although, I do agree that NULL--or better yet, nullptr--is better.

C++ Standard 18.1.4:

The macro NULL is an implementation-defined C++ null pointer constant in this Internnational Standard (4.10).

Footnote says:

Possible definitions include 0 and OL, but not (void*)0.

The C standard 6.3.2.3, paragraph 4 says:

Conversion of a null pointer to another pointer type yields a null pointer of that type. Any two null pointers shall compare equal.

If the intent was that programmer used 0 instead of NULL, then it isn't logical that they consistently use the word null. Also using NULL for pointers, and only for pointers, makes your code more readable. Or as Linus[1] put it

The fact is, people who write "0" are either living in the stone age, or are not sure about the type. "0" is an _integer_.

Wikipedia also warns users NULL null pointers can be non-0.

A null pointer has a reserved value, often but not necessarily the value zero, indicating that it refers to no object.

--Alfatrion (talk) 00:29, 7 April 2009 (UTC)[reply]

I agree with the logic of using NULL for abstract functions but I think it's nonstandard. Will it work with nullptr in C++0x, do you know? That is, could you do
virtual void foo() = nullptr; // or = NULL with a #define on NULL.
—Ben FrantzDale (talk) 01:07, 7 April 2009 (UTC)[reply]

Using NULL as a pure-specifier[edit]

Whether 0 or NULL should be used where a null pointer constant is required is a style issue, and open to debate. It is however, irrelevant to the changes being made to the example source code, because a pure-specifier has nothing to do with pointers at all. The claim that 0 would not be fully portable is exactly backwards.

As stated in my initial edit summary, a pure-specifier shall always be " = 0".[1] On certain implementations, "= NULL" may compile, if NULL happens to be #defined to 0, It may just as well be #defined to (2-2) or 0L,[2][3] which is not a valid pure-specifier, even if some compilers may (erroneously) accept 0L or 0x0.[4][1] Again, a pure-specifier is completely unrelated to null pointer constants, and must be " = 0". decltype (talk) 08:55, 7 April 2009 (UTC)[reply]

Your ride. I viewed it as an pointer and thats not quite ride. --Alfatrion (talk) 17:15, 7 April 2009 (UTC)[reply]
  1. ^ a b ISO/IEC (2003). ISO/IEC 14882:2003(E): Programming Languages - C++ §9.2 Class members [class.mem]
  2. ^ ISO/IEC (2003). ISO/IEC 14882:2003(E): Programming Languages - C++ §18.1 Types [lib.support.types] para. 4
  3. ^ ISO/IEC (2003). ISO/IEC 14882:2003(E): Programming Languages - C++ §4.10 Pointer conversions [conv.ptr] para. 1
  4. ^ http://gcc.gnu.org/ml/gcc-patches/2004-02/msg02318.html

Confusion[edit]

I regret to say that this is one of the most opaque explanations I have ever read. It does not really explain it at all. Any article that you have to re-read to understand what it's trying to explain has failed. —Preceding unsigned comment added by Curmudgeon99 (talkcontribs) 11:25, 6 April 2010 (UTC)[reply]

If you could provide some more specific criticisim, I'm sure people would be happy to improve it. Is there anything particular you found opaque? —Ben FrantzDale (talk) 15:33, 6 April 2010 (UTC)[reply]

When you describe a design pattern you should first explain the situation you are trying to solve and then explain how the design pattern solves the problem. Use a realistic example where the design pattern is the correct one to use for the situation. Developers who learn a design pattern will often make every effort to use it in any situation because they believe it must be "good design" to use design patterns, but use them when the situation does not call for this particular pattern to be used (possibly Abstract Factory, which is often used in a similar kind of problem to Visitor). —Preceding unsigned comment added by 212.58.232.179 (talk) 08:23, 26 July 2010 (UTC)[reply]

I've found lots of different explanations about the Visitor Pattern in the Internet. Actually, there are several variations of the pattern, which try to address problems not properly covered by the classical solution proposed to it. In particular, I find implementations full of visitA, visitB, visitWhatever, acceptA, acceptB, acceptWhatever absolutely wrong, IMHO. I've written an article which exposes real world use cases, uncovering why this pattern is needed and how it should be implemented in order to scale, still being clean, neat and absolutely flexible. My article is available here. If you guys find something useful, please feel free to copy and that's it. Thanks Frgomes (talk) 23:56, 29 January 2011 (UTC)[reply]

Vacuous comments[edit]

Two lines in the car example have accompanying comments:

interface CarElement {
    void accept(CarElementVisitor visitor); // CarElements have to provide accept().
}

and

return elements.clone(); // Return a copy of the array of references.

Each comment is literally an English transliteration of the meaning of the code near it. Comments that merely recapitulate the meaning of the code they adorn are worthless, except possibly to a reader who's unfamiliar with the programming language in which the code is written. Anyone who knows Java already has all the information these comments convey, because it's plainly apparent from the source code itself.

Not wanting to passive-aggressively remove the comments myself, I'm leaving this message here instead, imploring whoever wrote the code to remove them.

71.197.144.116 (talk) 05:14, 25 May 2010 (UTC)[reply]

I would defend the second as the reader might not know java very well hence not knowing about the clone method. For the fisrt I would consider changing it to
interface CarElement {
    void accept(CarElementVisitor visitor); // CarElements must provide an accept method.
}

just to reinforce that the interface establishes a contract for classes that implement it.--Salix (talk): 08:52, 25 May 2010 (UTC)[reply]

Terminology and Perspective Problem[edit]

It is not correct to say that the visitor pattern "adds" functionality or "adds" virtual functions to the object or object structure. Doing so implies that dynamic modification is occurring. That is incorrect and therefore misleading...

The Visitor patterns simply walks an object structure and performs (visits) an operation on each element of that structure. That's it.

There are many ways this "visit" may occur. For example, the visit may...

  1. perform the operation directly against each element by casting it (explicitly or implicitly) to a common interface or parent type shared by all the elements in the structure;
  2. perform the operation directly against each element with a procedure that detects and applies a type specific operation to each element; or
  3. pass a delegate, function pointer, or object hosting the operation as a method or set of type specific methods to each element through a common procedure (defined by a common parent interface or type) which then invokes the provided operation to do whatever it does.

The visitor pattern is a simple concepts. It is useful to have a simple example to bring that fact home...

//defines the delegate or function point, Action, which accepts a Visitable element and returns void or nothing
delegate void Action( Visitable actionable )
//defines the class Visitable which supports visits through a Perform method
class Visitable
public void Perform( Action action)
action(this)
items = List Of Visitable{"Cat", "Dog", "Ball", 1, 5, 123, 3.14, new Image("c:\folder\image1.jpg")}
foreach( element in items )
element.Perform( delegate(e) {if (e is Numeric) e.ToString.Print else e.Print } )

Here, the conforming parent type, Visitable, has an Action method which accepts a delegate as the visitor operation. Action is expected to invoke the delegate, passing it's containing element. In this case, the delegate will query the type and perform an appropriate operation.

I believe this is a better explanation because it does not presume a great deal of prior knowledge (one of the purposes of explanations in general). Subsequently, a more in depth treatment may be pursued with greater success with a reader who has a stable rock solid foundation. —Preceding unsigned comment added by 174.114.248.239 (talk) 18:18, 30 May 2010 (UTC)[reply]

Are these just fancy iterators[edit]

Like many of the people that have left comments here, I'm having a hard time understanding this article. But it seems like these are just fancy iterators. Am I wrong? 24.130.212.167 (talk) 08:03, 31 January 2012 (UTC)[reply]

They are related in that both are traversal patterns, but they are different. Using a visitor is a complementary approach to doing something with a collection of objects. In particular, a core idea of the visitor pattern is that you can prescribe different operations for different polymorphic (or static) types you visit. Also, with the visitor pattern, different objects have control over traversal order. For example, in Boost, you'll see visitors used for doing operations on heterogeneous statically-typed collections such as a std::pair<T,U>. You can't just iterate over a std::pair<T,U> because it has two different types, but you can apply a visitor that knows what to do with Ts and Us. The usual usage, though, is for polymorphic types. —Ben FrantzDale (talk) 14:28, 31 January 2012 (UTC)[reply]

Motivation paragraph?[edit]

Hi! What I miss most in the Visitor pattern article is a better description of the problem Visitor pattern intends to solve. And I'm not alone judging by the many discussions above, both recent (2012) and not-so-recent (2006). If I remember my GOF correctly, there was a section called "Motivation" to describe the real-world problem a pattern solves, and also a section called "Real world usages" or similar that gives some concrete examples (Motivation being more of an abstract description, Usages more concrete). The article about the Decorator pattern does have a Motivation paragraph already, which could be used as a style guide. Here's something to build upon:

Motivation. Large type hierarchies make adding hierarchy-wide operations (methods to every type) tedious, and if there are a lot of operations, the types become bloated and unmaintainable. For example, when representing the syntax of a program, adding a "pretty printer" operation to each syntax tree type adds noise to the source code. The visitor pattern solves this by factoring out the operation (pretty printing) to a separate class, which specializes in just pretty printing. So if you have many related types, and feel the urge to add more and more operations to (almost) every one of them, consider applying the Visitor pattern. --Objarni (talk) 10:57, 9 April 2012 (UTC)[reply]

I have written a longer example of when I think the Visitor pattern would be appropriate.
Motivation Consider the design of a 2D CAD system. At its core there are several types to represent basic geometric shapes like circles, lines and arcs. The entites are ordered into layers, and at the top of the type hierarchy is the drawing, which is simply a list of layers, plus some additional properties.
A fundamental operation on this type hierarchy is saving the drawing to the systems native file format. It seems relatively fine to add local save methods to all types in the hierarchy. But then we also want to be able to save drawings to other file formats, and adding more and more methods for saving into lots of different file formats soon clutters the relatively pure geometric data structure we started out with.
A naive way to solve this would be to maintain separate functions for each file format. Such a save function would take a drawing as input, traverse it and encode into that specific file format. But if you do this for several different formats, you soon begin to see lots of duplication between the functions, e.g. lots of type-of if statements and traversal loops. Another problem with this approach is how easy it is to miss a certain shape in some saver.
Instead, you could apply the Visitor pattern. The Visitor pattern encapsulates a logical operation on the whole hierarchy into a single class containing one method per type. In our CAD example, each save function would be implemented as a separate Visitor subclass. This would remove all type checks and traversal duplication. It would also make the compiler complain if you leave out a shape. --Objarni (talk) 20:02, 9 April 2012 (UTC)[reply]
OK I'm being a bit bold and publishing the above example as a motivation paragraph.--Objarni (talk) 09:46, 11 April 2012 (UTC)[reply]


@Objarni: I'd very much like to augment the Motivation section with an accompanying image, so it'll give a visual impression of what the text is trying to archive.

But I would prefer if someone else considered whether this change would be helpful.

Here's the augmented version (just having added the image and reference numbers to the text):

Motivation[edit]

Schematic Code Size Comparison On Visitor Pattern, vertically aligned, annotated.
Schematic Code Size Comparison On Visitor Pattern, vertically aligned, annotated

Consider the design of a 2D CAD system. At its core there are several types to represent basic geometric shapes like circles, lines and arcs. The entities are ordered into layers, and at the top of the type hierarchy is the drawing, which is simply a list of layers, plus some additional properties.

A fundamental operation on this type hierarchy is saving the drawing to the system's native file format. At first glance it may seem acceptable to add local save methods to all types in the hierarchy(image item 1). But then we also want to be able to save drawings to other file formats, and adding more and more methods for saving into lots of different file formats soon clutters the relatively pure geometric data structure we started out with(image item 2).

A naive way to solve this would be to maintain separate functions for each file format(image item 3). Such a save function would take a drawing as input, traverse it and encode into that specific file format. But if you do this for several different formats, you soon begin to see lots of duplication between the functions. For example, saving a circle shape in a raster format requires very similar code no matter what specific raster form is used, and is different from other primitive shapes; the case for other primitive shapes like lines and polygons is similar. The code therefore becomes a large outer loop traversing through the objects, with a large decision tree inside the loop querying the type of the object. Another problem with this approach is that it is very easy to miss a shape in one or more savers, or a new primitive shape is introduced but the save routine is implemented only for one file type and not others, leading to code extension and maintenance problems.

Instead, one could apply the Visitor pattern. The Visitor pattern encodes a logical operation on the whole hierarchy into a single class containing one method per type(image item 4). In our CAD example, each save function would be implemented as a separate Visitor subclass(image item 5). This would remove all duplication of type checks and traversal steps. It would also make the compiler complain if a shape is omitted.

Another motivation is to reuse iteration code. For example iterating over a directory structure could be implemented with a visitor pattern. This would allow you to create file searches, file backups, directory removal, etc. by implementing a visitor for each function while reusing the iteration code(image item 6).

Naming in UML Diagram[edit]

In the UML class diagram, the Visitor class implements the Visitable interface. In my opinion, this is bogus, language-wise. If something is "visitable", then it gets visited, it does not visit. It is the passive part. As such, the element being visited can be called "visitable", but not the visiting object (the visitor). 129.69.215.1 (talk) 10:49, 2 May 2013 (UTC)[reply]

Well spotted. The image is based on File:VisitorClassDiagram.png which uses Visitor for the interface and ConcreteVisitor for the implementing class. The new File:VisitorClassDiagram.svg was changed from a correct version [2] last year. I've reverted the change to the image.--Salix (talk): 11:50, 2 May 2013 (UTC)[reply]

There are some (copy/paste?) typos in the UML diagram: The Element subclasses are named ConcreteElementX, but the parameter types for the Visitor methods are ConcretesElementX. — Preceding unsigned comment added by 92.78.113.9 (talk) 10:19, 23 March 2017 (UTC)[reply]

Function Overloading required[edit]

Are you sure that Function overloading is required for the Visitor Pattern? Couldn't I just give the functions individual names, e.g. visitTypeA(TypeA a), visitTypeB(TypeB b).. instead of visit(TypeA a), visit(TypeB b). I don't think that missing function overloading hinders the implementation of this pattern. Ghinrael (talk) 12:29, 20 July 2013 (UTC)[reply]

I believe this is correct. The generic C++ code in the Implementation section in GOF is styled the same way using function names "VisitElementA(ElementA*)" and "VisitElementB(ElementB*)". - rfrankla (talk) 11:50, 21 April 2014 (UTC)[reply]

I thought the same. I translated the Java example to Go as straightforwardly as possible. I chose Go as it supports dispatch but not function overloading. The code works without problem and gives the same output. I just changed visit -> visitWheel, visitEngine, visitBody, visitCar as appropriate. I'll edit the article to remove the wrong statement. Bricegeumez (talk) 15:13, 18 December 2014 (UTC)[reply]

It would actually be good to the grid of overloading in the Java example: it just makes it harder to understand. User:Soundrabbit —Preceding undated comment added 10:56, 19 August 2015 (UTC)[reply]

Scala example[edit]

Is the Scala example correct? It isn't using double dispatch but instead just switching on the types, which contradicts both "The visitor takes the instance reference as input, and implements the goal through double dispatch" and "Another problem with [the naive] approach is that it is very easy to miss a shape in one or more savers, or a new primitive shape is introduced but the save routine is implemented only for one file type and not others, leading to code extension and maintenance problems. Instead, one could apply the Visitor pattern". I believe both those statements are correct, and that the Scala example does not properly demonstrate the visitor pattern. I know enough Scala to fix the example, if people agree, but I also would be in favour of removing it entirely as I don't think another example adds much to the article. Thoughts? ZoFreX (talk) 16:28, 23 June 2014 (UTC)[reply]

I've removed it entirely. I can't see what benefit adding another language implementation gives.--Salix alba (talk): 16:37, 23 June 2014 (UTC)[reply]

plagiarism[edit]

This article exhibits blatant plagiarism of the cited external link. In the "Definition" section we have:

"The Gang of Four defines the Visitor as: "Represent an operation to be performed on elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates."—″≤

The nature of the Visitor makes it an ideal pattern to plug into public APIs thus allowing its clients to perform operations on a class using a “visiting” class without having to modify the source."

and now compare this to the text at [3]:

"The Gang of Four defines the Visitor as:

Represent an operation to be performed on elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.

The very nature of the Visitor makes it an ideal pattern to plug into public API’s, thus allowing its clients to perform operations on a class using a “visiting” class without having to modify the source..."

Outrageous! — Preceding unsigned comment added by 87.82.250.210 (talk) 14:10, 7 January 2015 (UTC)[reply]

"Visitor" to "Church Encoding?"[edit]

Someone recently seemingly did a search-and-replace operation in this article on all instances of "visitor," switching them to "Church encoding." Looking at this article to get a real understanding of what the visitor pattern is, I found this quite confusing until I looked at the edit history and realized what happened.

Perhaps whoever made this change intended to draw a parallel between Church encoding and the visitor pattern, but if so it seems to me that it would be far more beneficial simply to add a section describing the parallels. I've reverted this change in the meantime.

Pretty Printing Example[edit]

In the state section of the article, a pretty printing example is references, however it's not actually included in the article, or linked to anywhere. Has this been accidentally removed or does this text accidentally remain?

9point6 (talk) 20:19, 3 February 2015 (UTC)[reply]

State[edit]

Not only does the State section of this article miss references or examples, I consider the gist of this section to be incorrect. Two main reasons:

  1. Implementing hierarchy state for a visitor is not trivial and does (for the classical visitor pattern described in the article) need change in the accept-methods of the class hierarchy. See [4] for an extended vistitor pattern which tries to solve this problem
  2. State is not something that is desirable[1] and especially in the given example unnecessary

Therefore I am deleting this section.

References

  1. ^ Abelson, Harold (1996). Structure and interpretation of computer programs. Cambridge, Mass. New York: MIT Press McGraw-Hill. pp. 229–236. ISBN 0262510871.)

Typo in Java example Output?[edit]

Isn't this:

  • Visiting body
  • Visiting engine
  • Visiting car
  • ...
  • Moving my body
  • Starting my engine
  • Starting my car

Supposed to read:

  • Visiting engine
  • Visiting body
  • Visiting car
  • ...
  • Starting my engine
  • Moving my body
  • Starting my car

or am I trippin? — Preceding unsigned comment added by 54.240.196.185 (talkcontribs)

I don't think so. If you look at the Car constructor we have
this.elements = new ICarElement[] { new Wheel("front left"),
            new Wheel("front right"), new Wheel("back left") ,
            new Wheel("back right"), new Body(), new Engine() };
so the body comes before the engine. --Salix alba (talk): 05:47, 5 November 2015 (UTC)[reply]

Article Java Tip 98 is obsolete as of Java 1.8[edit]

Regarding the tip for using reflection to implement a default visitor method found in the External links as "Article Java Tip 98: Reflect on the Visitor design pattern" — am I correct in thinking this is obsolete in Java 1.8, where interfaces may have default methods? Labalius (talk) 17:05, 8 November 2015 (UTC)[reply]

The link was dead, but the article can be found on info world at [5]. As its outdated I've removed the comment and external link.--Salix alba (talk): 08:34, 30 June 2020 (UTC)[reply]

C# "classic" example doesn't use visitor pattern[edit]

C# example STILL not a visitor pattern. The expressionprintervisitor should be a subclass of an abstract visitor. The example required that expressions know about printing. This is not what visitor is about. — Preceding unsigned comment added by 85.160.45.240 (talk) 00:22, 10 November 2021 (UTC)[reply]

The C# classic example just uses an overridden "Print" method on each subclass and doesn't actually use the visitor pattern at all. This incorrect example is confusing to those who are trying to understand what the visitor pattern is, and should be corrected or removed. — Preceding unsigned comment added by 73.187.218.254 (talk) 16:39, 4 September 2016 (UTC)[reply]

Yes I was about to make the same comment. The C# example is wrong and misunderstands the Visitor pattern because it requires the visitor to understand the structure of a Car. Whereas the point of the visitor pattern is that the structure knows itself and is responsible for its own traversal. If the internal organization of a car or the order in which elements must be visited is changed, the visitor should be unaffected. Houseofwealth (talk) 05:04, 30 June 2020 (UTC)[reply]

OK I've removed the section. Is the dynamic example OK? --Salix alba (talk): 07:21, 30 June 2020 (UTC)[reply]
No, that example failed at runtime, didn't compile, and didn't use the Visitor pattern. I fixed it for you. 99.16.142.154 (talk) 16:08, 23 August 2020 (UTC)[reply]
I looked into it more: it works on .NET Core but not .NET Framework because none of your types are public. .NET Framework wants dynamic to use public methods, .NET Core is more YOLO. I think if we're trying to teach people a design pattern we should shy away from fanciness like this! 99.16.142.154 (talk) 12:47, 25 August 2020 (UTC)[reply]

Suggested change to the Smalltalk example to satisfy the visitor pattern[edit]

The current Smalltalk example delegates the behavior to each object rather than separating the logic in a visitor? The following tweaked version puts the printing logic into the ExpressionPrinterVisitor rather than in each Expression subclass:

"There's no syntax for creating a class. Classes are created by sending messages to other classes."
WriteStream subclass: #ExpressionPrinterVisitor
    instanceVariableNames: ''
    classVariableNames: ''
    package: 'Wikipedia'.

ExpressionPrinterVisitor>>write: anExpression
    "Visit given expression"
    ^ anExpression accept: self.

ExpressionPrinterVisitor>>visitLiteral: aLiteral
    "Print a Literal object"
    self nextPutAll: aLiteral value asString.

ExpressionPrinterVisitor>>visitAddition: anAddition
    "Print an Addition object"
    self
        nextPut: $(;
        nextPutAll: anAddition left asString;
        nextPut: $+;
        nextPutAll: anAddition right asString;
        nextPut: $).

Object subclass: #Expression
    instanceVariableNames: ''
    classVariableNames: ''
    package: 'Wikipedia'.

Expression subclass: #Literal
    instanceVariableNames: 'value'
    classVariableNames: ''
    package: 'Wikipedia'.

Literal class>>with: aValue
    "Class method for building an instance of the Literal class"
    ^ self new
        value: aValue;
        yourself.

Literal>>value: aValue
  "Setter for value"
  value := aValue.

Literal>>value
  "Getter for value"
  ^ value.

Literal>>accept: aVisitor
    "Delegate behaviour to visitor which must implement visitLiteral"
    ^aVisitor visitLiteral: self.

Expression subclass: #Addition
    instanceVariableNames: 'left right'
    classVariableNames: ''
    package: 'Wikipedia'.

Addition class>>left: a right: b
    "Class method for building an instance of the Addition class"
    ^ self new
        left: a;
        right: b;
        yourself.

Addition>>left: anExpression
    "Setter for left"
    left := anExpression.

Addition>>left
    "Getter for left"
    ^ left.

Addition>>right: anExpression
    "Setter for right"
    right := anExpression.

Addition>>right
    "Getter for right"
    ^ right.

Addition>>accept: aVisitor
    "Delegate behaviour to visitor which must implement visitAddition"
    ^aVisitor visitAddition: self.

Object subclass: #Program
    instanceVariableNames: ''
    classVariableNames: ''
    package: 'Wikipedia'.

Program>>main
    | expression stream |
    expression := Addition
                    left: (Addition
                            left: (Literal with: 1)
                            right: (Literal with: 2))
                    right: (Literal with: 3).
    stream := ExpressionPrinterVisitor on: (String new: 100).
    stream write: expression.
    Transcript show: stream contents.
    Transcript flush.

This way if any new program logic needs to be added, a new visitor class can be created which uses the visitLiteral or visitAddition selectors rather than having to alter the Literal or Addition classes. Smalltalker2 (talk) 17:35, 22 January 2022 (UTC)[reply]

Both are a bit complex and can be simplified. On the other hand, I would make a separate class for each entity: ExpressionPrinter and LiteralPrinter and invoke accordingly. It's good to break down example into steps, so it's easier to consume. AXONOV (talk) 13:05, 26 January 2022 (UTC)[reply]

@Alexander Davronov: Thanks, I agree that the previous version (and the above) are not presented well and should be split into more digestible parts. The previous example was definitively not the visitor pattern in that it did not separate the algorithm (printing) from the object structure (the expression types). Whether you split the visitor into smaller sub-objects as you suggest is perhaps a matter of taste, although that's not how the pattern was presented by the GoF, or in the other languages' examples in this article. Smalltalker2 (talk) 17:35, 26 January 2022 (UTC)[reply]

Breaking down the above:

In Smalltalk we can first define Expression objects:

"There's no syntax for creating a class. Classes are created by sending messages to other classes."
Object subclass: #Expression
    instanceVariableNames: ''
    classVariableNames: ''
    package: 'Wikipedia'.

These can be sub-classed to useful types such as a literal expression type, which must respond to the #accept: method:

Expression subclass: #Literal
    instanceVariableNames: 'value'
    classVariableNames: ''
    package: 'Wikipedia'.

Literal class>>with: aValue
    "Class method for building an instance of the Literal class"
    ^ self new
        value: aValue;
        yourself.

Literal>>value: aValue
  "Setter for value"
  value := aValue.

Literal>>value
  "Getter for value"
  ^ value.

Literal>>accept: aVisitor
    "Delegate behaviour to visitor which must implement visitLiteral"
    ^aVisitor visitLiteral: self.

And similarly for an addition expression type:

Expression subclass: #Addition
    instanceVariableNames: 'left right'
    classVariableNames: ''
    package: 'Wikipedia'.

Addition class>>left: a right: b
    "Class method for building an instance of the Addition class"
    ^ self new
        left: a;
        right: b;
        yourself.

Addition>>left: anExpression
    "Setter for left"
    left := anExpression.

Addition>>left
    "Getter for left"
    ^ left.

Addition>>right: anExpression
    "Setter for right"
    right := anExpression.

Addition>>right
    "Getter for right"
    ^ right.

Addition>>accept: aVisitor
    "Delegate behaviour to visitor which must implement visitAddition"
    ^aVisitor visitAddition: self.

Then to add new logic separate from these existing classes (and without the need to modify their structure) we can define a visitor, for example for printing:

WriteStream subclass: #ExpressionPrinterVisitor
    instanceVariableNames: ''
    classVariableNames: ''
    package: 'Wikipedia'.

ExpressionPrinterVisitor>>write: anExpression
    "Visit given expression"
    ^ anExpression accept: self.

ExpressionPrinterVisitor>>visitLiteral: aLiteral
    "Print a Literal object"
    self nextPutAll: aLiteral value asString.

ExpressionPrinterVisitor>>visitAddition: anAddition
    "Print an Addition object"
    self
        nextPut: $(;
        nextPutAll: anAddition left asString;
        nextPut: $+;
        nextPutAll: anAddition right asString;
        nextPut: $).

Here the visitor needs to define methods #visitLiteral and #visitAddition in order to be accessed by the original expression objects. Finally we can use these objects to print an expression:

Object subclass: #Program
    instanceVariableNames: ''
    classVariableNames: ''
    package: 'Wikipedia'.

Program>>main
    | expression stream |
    expression := Addition
                    left: (Addition
                            left: (Literal with: 1)
                            right: (Literal with: 2))
                    right: (Literal with: 3).
    stream := ExpressionPrinterVisitor on: (String new: 100).
    stream write: expression.
    Transcript show: stream contents.
    Transcript flush.

This could benefit from further description but I think the logic is clearer Smalltalker2 (talk) 17:48, 26 January 2022 (UTC)[reply]

Good job. Do we have sources on where these "Expression/Left/Right" were all taken? As I see every example basically implements the code... Any thoughts? AXONOV (talk) 07:40, 27 January 2022 (UTC)[reply]

Examples & Uses[edit]

Jan 25, 2022, 16:24 - «Reverted 1 edit by 2600:1700:9E30:1590:10E2:39C9:D5DE:8DCA talk): Rv unverified, and etc.»
Jan 25, 2022, 03:22 - «Undid revision 1067490968 by Drmies talk) This is an accurate explanation of the Visitor Design Pattern and it gives a great example of a test implementation of this pattern. It is important to explain these design patterns with code examples because these patterns must themselves be implemented. If you don't find it useful Drmies, it doesn't mean others don't.»
Jan 23, 2022, 06:19 - «Undid revision 1067349395 by Drmies talk)»
Jan 23, 2022, 01:17 - «rm list of examples: we're an encyclopedia, not a collection of examples of unverified code»

@Drmies: I would rather tentatively agree with IP and propose to request citations first. Even though (admittedly), the #Uses section has been added a long time ago ([Jun 20, 2017, 16:02]) I don't think that blanking examples was useful. There might be sources that well support such examples. Folks who read article don't suspect that the information is unsourced so they don't bother to add any and take it (info) as granted. {{more citations needed}} at the top of the page should fix this. My best.

AXONOV (talk) 17:48, 25 January 2022 (UTC)[reply]

  • Alexander, if you can improve the article, that would be good. At the very least we need to have material in here that, in all its coding complexities (a language spoken by a few), can be verified to be matching to an authoritative text. Drmies (talk) 18:01, 25 January 2022 (UTC)[reply]
    I agree. Added a few sources and tag. Vanderjoe who made a substantial contribution to the article apparently has left wikipedia. If you remove something again please leave links to examples on Wikibooks if possible, see links below. Best. AXONOV (talk) 13:18, 26 January 2022 (UTC)[reply]
  • Salix alba, simply restoring a ton of unverified content while admitting that a ton of content is too much, that's not really helpful. Drmies (talk) 18:34, 25 January 2022 (UTC)[reply]
I've cut down the number of example, its still too much, and a good reference for these is needed.
Wikipedia:WikiProject Computer science/Manual of style#Code samples has some guidance, it does suggest a psudo-code example, this might be a way round the language choice.
For a reference implementation, the Java Standard Library has a java.nio.file.FileVisitor interface, and there is an example usage there.--Salix alba (talk): 19:27, 25 January 2022 (UTC)[reply]
As a side note we already have few examples of visitor patterns elsewhere (e.g. C++ example or java one).
I have a nice book on OOP programming (1997) I used as reference for Container (abstract data type). It has a dedicated subsection called 15.4 Iteration where a case of visitor pattern use is explained so I'm going to cite it if nobody minds. AXONOV (talk) 07:47, 26 January 2022 (UTC)[reply]