Visitor pattern and separating iteration

Discussion in 'Python' started by Karsten Wutzke, Jul 22, 2010.

  1. 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
    Karsten Wutzke, Jul 22, 2010
    #1
    1. Advertising

  2. >         # "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
    Karsten Wutzke, Jul 22, 2010
    #2
    1. Advertising

  3. Karsten Wutzke

    Ian Guest

    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
    Ian, Jul 22, 2010
    #3
  4. On 22/07/2010 12:03, Karsten Wutzke wrote:
    > 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.
    Mark Lawrence, Jul 22, 2010
    #4
  5. On 22 Jul., 22:25, Ian <> wrote:
    > 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
    Karsten Wutzke, Jul 23, 2010
    #5
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Martin Burger
    Replies:
    0
    Views:
    820
    Martin Burger
    Jul 18, 2005
  2. Replies:
    1
    Views:
    287
    mlimber
    Jan 25, 2006
  3. Giovanni Azua
    Replies:
    0
    Views:
    424
    Giovanni Azua
    Nov 30, 2007
  4. C#
    Replies:
    3
    Views:
    315
    Peter Morris
    Aug 1, 2008
  5. aaragon
    Replies:
    9
    Views:
    684
    aaragon
    Aug 14, 2008
Loading...

Share This Page