[e-lang] templateTermVisitor
Mark Miller
erights at gmail.com
Fri Dec 1 21:14:12 CST 2006
[Much of the following records a further conversation with Dean. --MarkM]
On 11/30/06, Dean Tribble <tribble at e-dean.com> wrote:
> Without using extends, the visitor would need to be something like
>
> def findFree := templateVisitor(def _ { to ...})
>
> so that the recursive invocation would dispatch correctly for all node
> types. That seems clumsier, but I'd be happy if you can propose a pattern
> that doesn't require extends.
For reasons I hope to clarify below, I'll modify your example by
naming the argument object:
def findFree := templateVisitor(def inner { to ...})
Another syntax for expressing the same semantics is
def findFree
def inner { to ...}
bind findFree := templateVisitor(inner)
Let's call this, "template composition", as contrasted with "template
inheritance":
def findFree extends templateVisitor(findFree) { to...}
Let's call the object directly defined and returned by templateVisitor
the "generic visitor", since its local behavior -- visit/1 and
visitAll/1 -- is independent of what we're visiting or what we're
supposed to do with it. Let's call the object defined to have the
methods above the "specific visitor" for the obvious reason. In
template composition, "findFree" is the generic visitor and "inner" is
the specific visitor. In template inheritance, "findFree" is the
specific visitor and "super" is the generic visitor. In both cases,
the generic visitor knows the specific visitor as "self".
When either composition or inheritance will do the job, then the
following must hold:
* findFree's clients don't use any operations other than those defined
by the generic visitor.
If they did, then they'd fail under template composition, since no
other operations are
exposed.
* The definer of findFree does not need to override the generic
operations as seen by
findFree's clients, because under the above template composition
pattern he can't.
When either will do, I would argue that template composition should be
preferred, because it is safer and semantically simpler.
Unfortunately, it is syntactically more complex, but so it goes.
When I spoke to Dean, I though it could be up to templateVisitor's
client as to which pattern to use, and that templateVisitor was
compatible with either choice. If so, that would be cool, especially
if it applied to E's inheritance pattern in general. Unfortunately, it
does not hold, either in general or in this case. The generic visitor
made by templateVisitor has the method
to visitAll(nodes) {
def res := [].diverge()
for n in nodes { res.push(self.visit(n)) }
return res.snapshot()
}
This method will fail under template composition, as self will be
bound to the specific visitor, which neither responds to nor forwards
the visit/1 method. The sad but unsurprising conclusion is that the
designer of a reusable parameterizable abstraction like
templateVisitor usually must chose whether it is to be reused via
inheritance or composition.
--
Text by me above is hereby placed in the public domain
Cheers,
--MarkM
More information about the e-lang
mailing list