Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [cme-dev] Visiting Concerns

Hi Harold,

Thanks for responding! I agree that composition is cleaner and more flexible than visitor in a number of ways and so I'm sympathetic, philosophically, to your case. On the other hand, this has practical limitations. You mention, rightly, that composition does not manage traversal and in cases where the datastructure is simple this is no problem but if it is complex it's a bit burdensome for the client. Moreover, there is the issue of encapsulation. It would be nice for the client not to *have to know* about the structure of data. Now admittedly even with a visitor we often do (I'm thinking of cases where we might have nested visitors) but it is a *bit* more declarative seeming. That is, I contend that:

	composite.accept(new CompositeVisitor() {
		void visit(BranchA b) {
			b.accept(new BranchAVisitor() {
				//...
			}
		void visit(BranchB b)
			b.accept(new BranchBVisitor() {
				//...
			}
	}

is nicer than:

	Branches [] br = composite.getBranches();
	for (int i 0; i < br.length; ++i) {
		Branch branch = br[i];
		if (branch instanceof BranchA) {
			Nodes [] nodes = ((BranchA)branch).getNodes();
			//traverse nodes...
		}
		if (branch instanceof BranchB) {
			// do something else...
		}
		//...
	}


In the end, I agree with you that Visitor should be replaced by composition in cases where it is being used to support a kind of open-class pattern. On the other hand, I think it might be just the trick if you are trying to encapsulate traversal. In my particular case, this is just what I was looking for --- I didn't want to have to "look behind the curtain" to build my representation of Concerns.

Having said all this it would probably be useful for me to describe a bit of my motivation. My interest in the CME is in the context of designing a system (with Andrew Black) that enables programmers to view and manipulate their programs from a number of (equally first-class) perspectives. Views in this system are derived from Concerns and are reified into editable textual representations. Edits to these representations directly effect the underlying model. There are many details to work out here but in the short term we are looking at a way to take extracted Concerns and transform them into the abstract syntax of a simple language that supports crosscutting views. In this language an "implementers of ..." concern derived from the query:

	method * speak()(..)

run over the 'feline' package might translate into abstract syntax that produces the following "row-centric" concrete view:

	String speak()
		case Feline { return "prrrrr..."; }
		case Tiger  { return "grrrrr"; }
		case Lion   { return "growl!"; }

that when edited effects the methods in the underlying classes.

Of course this just scratches the surface of the story but hopefully gives you a taste. If you're interested, I'd be happy to tell you more. As for you offer to help get me get set up using the ConMan composition mechanism, I'd love to take you up on it. I also agree that this would be mutually beneficial. (And maybe my instincts about Visitors won't bear out!) In any event, it would be interesting to find out.


Thanks again,


phil








Harold Ossher wrote:
Hi Philip,

It's really interesting that you raised this. There is, as you observed, no
visitor support for concern models. This is in large part because we always
tend to think of composition as a better realization of visitors than the
usual approach. Here's how it would work, illustrated with your example.

Typically, the visitor pattern is used to extend an interface - to add some
new capability across an inheritance hierarchy (like the concern model),
implement it separately for selected specific classes, and use dispatch to
pick the right implementation, There's also the actual traversal, but let's
ignore that for a moment.. So, using a composition approach, you write an
extension to the interface, to the top-level abstract class (to do nothing)
and to the classes you actually want to extend. These classes can be
top-level classes, or inner classes within a containing "visitor" class, in
your own project. In your case:

public interface ConcernModelElement {
      public void collectAdvice(Collection c);  // Additional method
}

public class AbstractConcernModelElementImpl implements
ConcernModelElement, org.eclipse.cme.conman.ConcernModelElement {
      public void collectAdvice(Collection c) {} // Default implementation
}

public class Advice implements ConcernModelElement,
org.eclipse.cme.conman.Advice {
      public void collectAdvice(Collection c) {  // Specific implementation
            c.add(this.getDefinition());
            // c.add(this.getAdviceArtifact);  There is not a special
method getAdviceArtifact, but this is how you'd use it if there were.
      }
}

Now you can compose this extension with ConMan (or the cme jar), and call
collectAdvice like any other method. So you would iterate over the elements
you care about, calling this method. The same, or separate, extensions
could add other methods.

Conceptually, this approach has some advantages over the standard
implementation of visitor, such as the ability to add methods with a
variety of parameters and return types and avoidance of double dispatch. It
doesn't handle the traversal, through. You could do that by implementing
the collectAdvice() method for GroupImpl, the top-level collection in the
concern model hierarchy, to iterate over the elements. Unfortunately, there
is no way to make this generic across all extensions, as the usual visitor
pattern does, because a specific method name is involved (rather than a
visitor object).

Unfortunately, we don't yet have the tool support to make the composition
approach really convenient (some classpath manipulation, integration of
composition with the Eclipse build process, perhaps some refactoring/code
generation to help set up the structure, ...). Still, I'd be interested to
hear your thoughts on this approach, and if you have time and are feeling
adventurous, we can help you set this up by hand using the lower-level
composition support we do have. Together we'd learn something about what is
really needed to support this well. (We might hit some bugs or limitations
in the course of this, which we'd be happy to work on, but our time is
limited so we should discuss your time constraints.)

Regards, Harold



Philip Quitslund <pq@xxxxxxxxxx> Sent by: To cme-dev-admin@ecl cme-dev@xxxxxxxxxxx ipse.org cc Subject 12/13/2004 05:48 [cme-dev] Visiting Concerns PM Please respond to cme-dev



Hi all.

Forgive me if this is obvious (and it probably is!) but I'm puzzling over
how to
best traverse the structure of Concerns.  What I'm driving at is a way to
take a
  Concern and build my own abstract representation.  I was expecting some
kind
of visitor scheme but haven't found anything...

As a simple example, suppose I wanted to collect all the AdviceArtifacts in
a
Concern.  I'd like to avoid code that looks like this:

 /* final */ Collection adviceCollector = new ArrayList();

 ConcernModelElement cme =
  /* ProxyConcernModelElement */ pcme.getConcernModelElement();
 if (cme instanceof ConcernImpl) {
  ConcernImpl concern = (ConcernImpl)cme;
  QueryableRead elems = concern.getElements();
  for (Iterator iter = elems.iterator(); iter.hasNext();) {
   Object o = iter.next();
   if (o instanceof AdviceUnit) {
    adviceCollector.add(((AdviceArtifact)o).
     getAdviceArtifacts());
   }
   ...
  }
  ...
 }

preferring something more like this:

cme.accept(new ConcernVisitor() {
  void visit(AdviceUnit advice) {
   adviceCollector.add(advice.getAdviceArtifact());
  };
 );

(Admittedly this is an overly simple example, but you get the idea.)

What's the best way to programmatically explore the structure of Concerns?

Any help would be greatly appreciated.  Thanks!



-phil





_______________________________________________
cme-dev mailing list
cme-dev@xxxxxxxxxxx
http://dev.eclipse.org/mailman/listinfo/cme-dev




Back to the top