Visitor pattern and separating iteration

K

Karsten Wutzke

Hello,

I'm referring to

http://groups.google.com/group/comp.lang.python/browse_thread/thread/4f9ba9816fe4fd55#

I'm currently implementing what looks like a promising solution. I
have one problem though. My code generator isn't awfully complex, but
still I have problems trying to figure out where to put the iteration
code. Ideally, this should be in the classes the generator operates
on. Take the following Python code from my generator class:

def handleMethod(self, method):

# generate indent depending on object depth in tree
indent = self.generateIndent(method)

# "public final"
modifierString = ""

i = 0

for modifier in method.getModifiers():
if i > 0:
modifierString += " "
modifierString += modifier

i += 1

# "String firstName, String lastName"
parameterString = ""

i = 0

for parameter in method.getParameters():
if i > 0:
parameterString += ", "
parameterString += parameter.getType() + " " +
parameter.getName()

i += 1

code = indentString + modifierString + " " +
(method.getReturnType() is None and "" or method.getReturnType() + "
") + method.getName() + "(" + parameterString + ")"

code += "\n{"

# here the statements should go

code += "\n}"

return code

The place where the statements should go would require an iteration
over the statements. When looking at other code samples, you often see

def accept(self, visitor):
for child in self.getChildren():
child.accept(visitor)

visitor.visitMyClass(self)

Now, I am wondering how separation of iteration and actual code
generation can be done in my situation.

def accept(self, generator):
for child in self.getChildren():
child.accept(generator)

generator.handleMethod(self)

I could of course add a parameter to handleMethod which would be the
generated code for the statements, but is that design of any good use
then? I'm rather tempted to ditch the idea of separating iteration and
code generation, but then the use of the visitor pattern becomes more
and more questionable.

What is it I'm missing?

Karsten
 
K

Karsten Wutzke

        # "public final"
        modifierString = ""

        i = 0

        for modifier in method.getModifiers():
            if i > 0:
                modifierString += " "
            modifierString += modifier

            i += 1

And please don't comment on the code itself, as I'm just starting to
learn the Python API. The above should be

modifierString = " ".join(method.getModifiers())

Thanks
Karsten
 
I

Ian

Hi Karsten,

What is it I'm missing?
I think you are making it more complicated than it really is.

The visitor pattern is about bringing all the little bits that would
otherwise be scattered all over
many node classes into one visitor class. For code generation this means
that all the code generation is done
in your visitor class. For pretty-printing you have another visitor
class. For code optimization a third
visitor class.

If there is only one sequence in which the nodes should be visited, then
you can build it
in to the nodes of the tree.

If you need to visit your nodes in different orders you might be better
off building a separated
tree-walker class for each order. Thus you might have a
post-order-walker for use with the code
generating visitor, and a in-order-walker for a pretty-printing visitor.

The optimizing walker may need to take different routes through the tree
depending
upon what it finds. For example, it may compute the value of the RHS of
an assignment
before computing the address of the LHS, so it can make better use of
registers. Here the
visitor class itself needs to do the walking.

Regards

Ian
 
M

Mark Lawrence

Hello,

I'm referring to

http://groups.google.com/group/comp.lang.python/browse_thread/thread/4f9ba9816fe4fd55#

I'm currently implementing what looks like a promising solution. I
have one problem though. My code generator isn't awfully complex, but
still I have problems trying to figure out where to put the iteration
code. Ideally, this should be in the classes the generator operates
on. Take the following Python code from my generator class:

def handleMethod(self, method):

# generate indent depending on object depth in tree
indent = self.generateIndent(method)

# "public final"
modifierString = ""

i = 0

for modifier in method.getModifiers():
if i> 0:
modifierString += " "
modifierString += modifier

i += 1

# "String firstName, String lastName"
parameterString = ""

i = 0

for parameter in method.getParameters():
if i> 0:
parameterString += ", "
parameterString += parameter.getType() + " " +
parameter.getName()

i += 1

code = indentString + modifierString + " " +
(method.getReturnType() is None and "" or method.getReturnType() + "
") + method.getName() + "(" + parameterString + ")"

code += "\n{"

# here the statements should go

code += "\n}"

return code

The place where the statements should go would require an iteration
over the statements. When looking at other code samples, you often see

def accept(self, visitor):
for child in self.getChildren():
child.accept(visitor)

visitor.visitMyClass(self)

Now, I am wondering how separation of iteration and actual code
generation can be done in my situation.

def accept(self, generator):
for child in self.getChildren():
child.accept(generator)

generator.handleMethod(self)

I could of course add a parameter to handleMethod which would be the
generated code for the statements, but is that design of any good use
then? I'm rather tempted to ditch the idea of separating iteration and
code generation, but then the use of the visitor pattern becomes more
and more questionable.

What is it I'm missing?

Karsten

I suggest you google for "python patterns alex martelli". From what I've
read, he's forgotten more about Python and/or patterns than most of us
will ever know.

HTH.

Mark Lawrence.
 
K

Karsten Wutzke

Hi Karsten,

On 22/07/2010 12:03, Karsten Wutzke wrote:> What is it I'm missing?

I think you are making it more complicated than it really is.

The visitor pattern is about bringing all the little bits that would
otherwise be scattered all over
many node classes into one visitor class. For code generation this means
that all the code generation is done
in your visitor class. For pretty-printing you have another visitor
class. For code optimization a third
visitor class.

If there is only one sequence in which the nodes should be visited, then
you can build it
in to the nodes of the tree.

If you need to visit your nodes in different orders you might be better
off building a separated
tree-walker class for each order. Thus you might have a
post-order-walker for use with the code
generating visitor, and a in-order-walker for a pretty-printing visitor.

The optimizing walker may need to take different routes through the tree
depending
upon what it finds. For example, it may compute the value of the RHS of
an assignment
before computing the address of the LHS, so it can make better use of
registers. Here the
visitor class itself needs to do the walking.

Regards

Ian

My objects to iterate over are plain object-structures, composites. I
have only one code generation pass, so generating code and then pretty
printing is not intended/possible. I have many user options to
configure the code generation. The visitor pattern is ideal for that
matter, because I can keep the options in the generator rather than
scatter all the options into the object classes' accessor methods.
(making me think the visitor is just right and not more complicated
than needed)

I was just curious about separating the iteration code into the object
classes, because GoF said "The main reason to put the traversal
strategy in the visitor is to implement a *particular complex*
traversal, one that depends on the results of the operations on the
object structure." My code generator isn't really THAT complex (I
thought), but reviewing the latter part of the quote makes me believe
I was wrong. Code generation always depends on the previous results,
that is the children of a composite in the object structure. Now that
I realized it, I feel great about traversing in the visitor.

Python just has a few consequences that makes creating common
interfaces/abstract classes a little unusual. I'm just starting to
really love Python (or its API), though I don't feel I've already
discovered the core what it is really about.

Best regards
Karsten
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top