>From dougo@ccs.neu.edu Sun Nov 9 21:26:13 1997 >Subject: Re: Inline Visitors in Demjava > >Galen: thanks for the comments. Hope you don't mind my cc'ing them to >the dem alias. > >Galen Williamson writes: > > Point 1. this isn't the this that you think this is > > > > SomeClass { > > public void t() to SomeOtherClass { > > init > > (@ > > // right here, this _looks_ like it should refer to an instance > > // of SomeClass, but it really refers to an instance of > > // __V_SomeClass_t. > > // Obviously, this is an unavoidable result of the generation > > // of the separate visitor class (which also seems unavoidable). > > // But it really breaks the illusion of inlined visitors being > > // inline. > > @) > > } > > } > >I don't know what to do about this, except point it out in the >documentation. It might get less confusing when we add "start" >methods, which are executed right at the beginning of the traversal, >rather than when the visitor class is executed. The "host" variable >will be set to the starting object (in this case, SomeClass). >Similarly there will be a "finish" method called at the end of the >traversal. > > > Point 2. the construction of inlined visitors > > > > // from .cd: > > > > Vertex = Ident. > > > > Main = . > > > > Vertices = VertexList. > > VertexList = List(Vertex). > > List(S) ~ { S } . > > > > // from .beh: > > > > // This works: > > Vertices { > > public Vertices union(Vertices other) to Vertex { > > (@ Vertices un; @) > > before Vertices > > (@ > > if (other == null) { > > un = Vertices.parse(""); > > } > > else { > > un = other.union(null); > > } > > @) > >Again, this can be handled in the "start" method, which is called >after the visitor parts have been initialized from the arguments. > > > before Vertex > > (@ > > if (host != null && !un.contains(host)) > > un.addElement(host); > > @) > > return Vertices (@ un @) > > } > > > > // The Repetition-Buffer Rule makes the following necessary > > // so that we can do the normal list-things to the > > // Vertices wrapper class > > public boolean contains(Vertex v) to-stop Vertex_List > > { before Vertex_List (@ return_val = host.contains(v); @) } > > public void addElement(Vertex v) to-stop Vertex_List > > { before Vertex_List (@ host.addElement(v); @) } > > public boolean isEmpty() to-stop Vertex_List > > { before Vertex_List (@ return_val = host.isEmpty(); @) } > > public int size() to-stop Vertex_List > > { before Vertex_List (@ return_val = host.size(); @) } > > } > >This is pretty ugly... hopefully the Repetition-Buffer Rule will no >longer be needed when we allow repetition edges from construction >classes (but that's probably not going to happen real soon). > > > // This does not work: > > Vertices { > > public Vertices union(Vertices other) to Vertex { > > (@ Vertices un; @) > > init > > (@ > > if (other == null) { > > un = Vertices.parse(""); > > } > > else { > > un = other.union(null); > > } > > @) > > before Vertex > > (@ > > if (host != null && !un.contains(host)) > > un.addElement(host); > > @) > > return Vertices (@ un @) > > } > > } > > > > // which compiles to > > > > class Vertices { > > ... > > public Vertices union(Vertices other) { > > // why do we call the default constructor, > > __V_Vertices_union v0 = new __V_Vertices_union(); > > // and then use the set_ method? > > v0.set_other(other); > >Two reasons: 1. The default constructor is called in order to invoke >the "init" method. It's a little tricky (in fact maybe impossible; I >haven't figured out a way) to call the default constructor from all >the other constructors, because of the way calls to superclass >constructors work in Java. 2. Not all the parts of the visitor class >need to be specified in the argument list, nor do they have to be in >the same order; thus we'd have to generate constructors for every >possible combination and permutation of the visitor parts. Not really >feasible, obviously. But the set methods can be called in any order, >and not all of them have to be called, so it matches what we want. > > > __trav_union(v0); > > return v0.get_return_val(); > > } > > ... > > } > > > > // and > > > > class __V_Vertices_union implements Cloneable { > > ... > > public __V_Vertices_union(Vertices other) { > > super(); > > set_other(other); > > } > > Vertices un; > > public __V_Vertices_union() { > > if (other == null) { > > un = Vertices.parse(""); > > } > > else { > > un = other.union(null); > > } > > } > > ... > > } > > > > > > Unrelated Question: > > > > On a separate note, do you have any idea why the following didn't work at > > all? > > > > Vertex { > > /* > > public Ident dig_out_ident() to Ident { > > (@ Ident i; @) > > init (@ i = null; @) > > before Ident (@ i = host; @) > > return Ident (@ i @) > > } > > public boolean equals(Vertex other) to Ident { > > (@ boolean res; @) > > init (@ res = false; @) > > before Ident > > (@ > > res = host.equals(other.dig_out_ident()); > > @) > > return boolean (@ res @) > > } > > public String toString() to-stop Ident > > { before Ident (@ return_val = host.toString(); @) } > > > > // The above adaptive methods don't work, so we have the following > > // brittle versions! > > */ > > (@ > > public String toString() { > > return get_name().toString(); > > } > > public boolean equals(Object id) { > > return (id instanceof Vertex) && > > get_name().equals(((Vertex) id).get_name()); > > } > > @) > > } > >You can't attach visitor methods to terminal classes (e.g. Ident). >You could use a "to *" traversal and put wrappers around the edges >going to the terminal classes, but that's a little kludgey. That's >pretty much the reason for the Terminal Buffer Rule, to isolate the >brittleness in the buffer classes. In this particular case, of >course, you could just use the EqualVisitor (which essentially does >the "to *" traversal with wrappers on the edges). > >--Doug > >