Weaver/Yarn Pattern in Python
Ype Kingma
ykingma at accessforall.nl
Wed Jan 21 03:19:59 EST 2004
Christian Stork wrote:
> Hello everybody,
>
> I am using Python to prototype a compression algorithm for tree-shaped
> data, e.g., XML data or abstract syntax trees. I use a variant of the
> visitor design pattern--called weaver/yarn pattern--in order to
> traverse the tree that is being compressed or decompressed. I do not
> know of any other interesting application of the weaver/yarn pattern,
> but it seems like a very suitable subject of study for different
> implementation strategies. Essentially, I am asking for input on my
> design decisions.
>
> First, let me give you a simple example of the traditional visitor
> pattern. The following diagram illustrates a depth-first traversal of
> a mini tree by a visitor. The basic idea is that the tree accepts a
> visitor and helps it to do a kind of type-dispatch based on the kind
> of nodes.
>
...
>
> The advantage of this ping-pong between the tree and visitor v is that
> v encapsulates related processing instructions. Several different
> visitors can be maintained independently of each other and without
> forcing changes to the tree node classes. The tree nodes only need to
> provide a node.accept(visitor) method. Type-checking can ensure
> the match between the visitor and the tree data structure.
>
> Normally, visitors encapsulate different processing passes, which are
> run one after the other, each time traversing the whole tree. I have
> implemented the compression of trees as several (sub)visitors c1..cN
> even though they could have been implemented as one big visitor.
> Besides the easy recombinability of visitors this has the added
> advantage that I can use the same visitors for compression and
> decompression where this is appropriate.
>
> But now I have a problem when decompressing. In order to run one
> visitor after another the first one expects to traverse the whole
> tree. But this is impossible in case of a decompressor. It lies in
> the very nature of the application that the tree is being constructed
> while the visitors work on it. Conceptually the solution is easy.
> The decompression subvisitors d1..dM have to process the partially
> available tree upto the point of traversal where it is available. At
> each node execution has to iterate over the applicable code of d1..dM
> in the given order. This necessitates a decomposition of visitors
> into something that we call yarns and these yarns are weaved by one
> visitor, which we call the weaver. Thus the name "Weaver/Yarn
> Pattern" for this variation of the visitor pattern.
>
> The following exemplifies my current implementation of the w/y pattern
> for a recursive descent (ie depth-first traversal) visitor. For each
> (sub)visitor d1..dM the former d<i>.visitX(x) method is divided into
> several y.weaveX_...() methods. At entry and exit the weaver invokes
> y.weaveX_First() and y.weaveX_Last(). Each descent into a child is
> surrounded by y.weaveX_Before(kidno) and y.weaveX_After(kidno) method
> calls.
>
...
>
> By now it should be obvious that the boilerplate for this approach
> becomes quite extensive and it would be desirable to reduce it. To
> mitigate the problem I did three things:
>
> - Automatically generate templates for yarn classes. The actual code
> can be filled in. Disadvantage: No convenient way to deal with
> changes to the tree data structure.
>
> - The node.accept(weaver) methods are changed to call a "generic"
> weaver.weave(node) method (instead of weaver.visitX(node)), which
> hackishly constructs all the calls to the yarns by assembling the
> method names from the __class__.__name__ and one of "First", "Last",
> "Before", and "After".
>
> This solution does pretty much what I want:
>
> - Writing selected yarn methods allows me to express with little
> overhead /what/ code to execute /when/ in the weaving process.
>
> - Once the weaver/yarn interaction machinery is set up correctly, the
> debugger points me to real code in case of bugs. This is an
> advantage over approaches that create classes at runtime, e.g., use
> of metaclasses or the "new" module.
>
> OTOH, I'm not perfectly happy with this solution since it's totally
> "hackish". For example, I have to use a function, hand-written
> specifially for this purpose, in order to "type-check" the
> correspondence of the tree types and the yarns.
>
...
Have a look at aspect oriented programming:
http://www.ccs.neu.edu/home/lieber/AOP.html
In theory it sounds like a good match for what you need.
I don't know how well Python supports this, perhaps you
can use a metaclass for this, but I'm not sure.
Have fun,
Ype
--
email at xs4all.nl
More information about the Python-list
mailing list