Re: [acyclic visitor]The "accept" operation of an object



Responding to Ram...

  I am quite new to the visitor-pattern. I did not understand it
  completely when I read about it first, but then I have
  re-invented it, when I needed to interpret a parse-tree in two
  different ways - and reinventing always helps me to
  understand. Still some question have arosen:

The first thing to understand is why most of the GoF patterns exist. Most of them address relationships that are too complicated to express as a simple association. The complication is usually dynamic in nature (i.e., who the specific participants are must be determined at run time). In addition, there are usually issues of behavior substitution basecon collaboration context. For most of the GoF patterns the solution is delegation, subclassing, polymorphic substitution, and dynamic relationship instantiation. Thus patterns like Strategy, State, Composite, etc. all kind of look the same superficially because they all have these elements somewhere.


Visitor is somewhat unique in that it deals with a very special problem where the collaborating objects are from subclasses in different trees but they need to access the specializations of the subclass (i.e., there is no behavior substitution). In addition, an object from any subclass in one tree may collaborate with an object of any subclass in the other tree. In effect one has a set of 1:1 relationships between each subclass in one tree with every subclass of the other tree. IOW, one has a combinatorial complete set of all possible 1:1 relationships between subclasses of two trees. Trying to explicitly "hard-wire" each of those relationships can get very messy. Visitor provides an elegant "cookbook" mechanism for implementing those relationships.


My "accept" operation does not return "void" but a type called "Value". Actually the meaning of this accept-operation is the Value of this object as given by the interpreter, which is the parameter (visitor) of this accept operation. Is there anything wrong with "accept" not returning "void" but a "Value"?

Yes, unless you are just using the return to indicate a failure in the acceptance. What Accept is really doing is establishing a temporary 1:1 relationship between two objects from subclasses in different trees. At that point there is no collaboration yet, so there is no reason to return a value.


If you look at the sequence diagram on pg. 335, the collaboration actually takes place between aConcreteVisitor and either aConcreteElementA or aConcreteElementB when the call to OperationA() or OperationB(), respectively, is made. That is when the relationship assigned by invoking Accept() is actually navigated for the collaboration. So if a value needs to be returned from the collaboration, then it should be OperationA() or OperationB() that does so.


I also would like to implement the acyclic visitor. A page on the web gives IIRC an implementation in Java similar to this:

void accept( Visitor visitor )
{ if( visitor instanceof MyVisitor )
  { MyVisitor myVisitor =( MyVisitor )visitor;
    visitor.visit( this ); }}

  The "instanceof" will prevent a cast-exception. I am not
  sure if I understand the situations which might lead to
  this situation, but I would like not to silently ignore
  such a call, but to get an exception indeed, so I would like
  to remove the test to get:

What this code seems to be doing is dealing with the situation where a object may not have collaborations with objects from all of the subclasses of the other tree. (I am not keen on that usage but since it is for other reasons unrelated to Visitor, let's not go there.)


If you want to respond to that situation with this code, you just need an else clause to throw the exception.


void accept( Visitor visitor ) { MyVisitor myVisitor =( MyVisitor )visitor; visitor.visit( this ); }

  Because I do not return "void" I also would have to
  return some dummy value in the case of a false value
  of the expression "visitor instanceof MyVisitor",
  and it is not obvious what such a value should be.

Another reason for not returning a value. B-)


Another question: I am creating a library for some container objects. One container class is called a "Room", for example. Even if such need never arose until today, I am thinking about inserting an "accept"-operation into all these classes by way of precaution for the clients. This might look like:

interface Visitor {}; // provided by my library once for all uses
interface Value {}; // provided by my library once for all uses
interface RoomVisitor { visit( Room ); };
class Room { ... public Value accept( Visitor visitor ) ... }

  Anything wrong with this idea? (Inserting an "accept"
  operation into many classes just for the case clients might
  need it, even if a situation, where it is needed, has
  not appeared yet?)

Yes. Solve the problem in hand, not problems that might be. The reason one uses the OO approach is so that when the world does change one can deal with the change fairly easily. That precludes the need to anticipate specific future changes. Visitor involves significant infrastructure and some indirection overhead. Why undertake that when it is not needed?



************* There is nothing wrong with me that could not be cured by a capful of Drano.

H. S. Lahman
hsl@xxxxxxxxxxxxxxxxx
Pathfinder Solutions  -- Put MDA to Work
http://www.pathfindermda.com
blog: http://pathfinderpeople.blogs.com/hslahman
(888)OOA-PATH



.



Relevant Pages

  • Re: Visitor and Observer combined?
    ... Whether the second tree is a delegation or a direct problem space ... subclass properties are accessed). ... element and vice versa or else they wouldn't be part of the pattern. ... it can be used to play and manipulate MIDI files. ...
    (comp.object)
  • Re: Approach for the following scenario?
    ... an instance of the right subclass but in the previous paragraph you have ... The problem lies in ordinary collaboration during the solution. ... access a subclass' specialized properties, ... effectively a downcast navigation of the subclassing relationship. ...
    (comp.object)
  • Re: How to draw on "Microsoft Web Browser" control?
    ... I am doing semantic analysis on the HTML DOM tree, ... Draw on existing elements doesn't change the structure of the html ... which is a subclass of CWnd. ...
    (microsoft.public.vc.mfc)
  • Re: forEach and Casting
    ... superclass is because I needed a common class to use with the tree. ... the underlying information in each subclass is very different ... different depending on the class in question. ...
    (comp.lang.java.programmer)
  • Re: __init__(self, *args, **kwargs) - why not always?
    ... > A subclass may be a specialized case, ... These will work even if tree is later enhanced to keep ... indicates that the base class also needed to see position. ... required by passing position in your original example. ...
    (comp.lang.python)