From: Thomas Jollans on
On 07/16/2010 11:00 AM, Jean-Michel Pichavant wrote:
> Karsten Wutzke wrote:
>>> Yes, typo, I meant strictly.
>>>
>>>
>>
>> Damn, I mean strongly. At least not for identifying which methods to
>> call depending on the type/s.
>>
>> Karsten
>>
> Stringly is the perfect combination of strictly and strongly. Nice one :)

stringly typed sounds like "everything is a string" - doesn't Tcl do
that ? ^^

From: Mick Krippendorf on
Karsten Wutzke wrote:
> The visitor pattern uses single-dispatch, that is, it determines
> which method to call be the type of object passed in.

Say, in Python, I have an object o and want to call one of it's methods,
say m. Then which of possibly many methods m to call is determined by
the type of o, and nothing else (at least without further magic) -
hence, it is single dispatch. The VP uses two single dispatch calls (one
being a callback) to accomplish double dispatching.

Java has a form of multiple dispatch through function overloading. In
fact, it's still single dispatch, because which of the targets
overloaded methods gets called is determined at compile time by the
staticly known types of the methods parameters, AKA the formal parameter
types.

Anyway. Although VP *uses* double dispatch, it does not necessarily rely
on function overloading. In Java the VP is most often implemented like this:

<java>

interface IASTNode {
void accept(IASTVisitor);
}

class IfNode implements IASTNode {
void accept(IASTVisitor visitor) {
visitor.visit(this);
}
}

class ElseNode implements IASTNode {
void accept(IASTVisitor visitor) {
visitor.visit(this);
}
}

interface IASTVisitor {
void visit(IfNode node);
void visit(ElseNode node);
...
}
class PrettyPrinter implements IASTVisitor {
public void visit(IfNode n) {
...
}
public void visit(ElseNode n) {
...
}
}

</java>

but it could as well be implemented like this:

<java>

interface IASTNode {
void accept(IASTVisitor);
}

class IfNode implements IASTNode {
void accept(IASTVisitor visitor) {
visitor.visitIfNode(this);
}
}

class ElseNode implements IASTNode {
void accept(IASTVisitor visitor) {
visitor.visitElseNode(this);
}
}

interface IASTVisitor {
void visitIfNode(IfNode node);
void visitElseNode(ElseNode node);
...
}
class PrettyPrinter implements IASTVisitor {
public void visitIfNode(IfNode n) {
...
}
public void visitElseNode(ElseNode n) {
...
}
}

</java>

If Java were *really* a multiple dispatch language, it wouldn't be
necessary to repeat the accept-code for every subclass. Instead a single
accept method in the base class would suffice. In fact, with true
multiple dispatch VP wouldn't even be needed.


Regards,
Mick.
From: Mick Krippendorf on
Hello,

Am 16.07.2010 09:52, Michele Simionato wrote:
> [os.path.walk vs os.walk]
> There is a big conceptual difference between os.path.walk and os.walk.
> The first works like a framework: you pass a function to it and
> os.path.walk is in charging of calling it when needed. The second works
> like a library: os.walk flattens the hierarchical structure and then
> you are in charge of doing everything you wish with it.
>
> os.walk is the Pythonic way, and you suggested to follow that
> approach; for instance elementTree and lxml (libraries for parsing XML
> data) work exactly that way. Actually one of the motivating examples for
> the introduction of generators in Python was their use in flattening
> data structure, i.e. exactly the pattern used by os.walk.

The Visitor Pattern isn't about traversing, so they could as well have
had an os.walk() that took a visitor object. Instead, it's about the
untangling of unrelated stuff. Not the traversing vs. everything else -
that's what iterators are for, like you said. But if you want to be able
to add new types of operations without ever touching the code of the
objects on which to apply those operations, then the VP is an easy way
to accomplish things:

<python>

class IfNode:
def apply(self, operation):
operation.handleIfNode(self)
....

class ElseNode:
def apply(self, operation):
operation.handleElseNode(self)
....

class PrettyPrinter:
def handleIfNode(self, if_node):
# print if_node pretty
def handleElseNode(self, else_node):
# print else_node pretty
....

class Interpreter:
def handleIfNode(self, if_node):
# interpret if_node
def handleElseNode(self, else_node):
# interpret else_node
....

class AST:
def apply(self, operation):
# apply operation to all nodes
....

some_ast = ...
some_ast.apply(PrettyPrinter())
some_ast.apply(Interpreter())

</python>

The traversing in AST.apply() is not really part of the pattern, it
could also be done in the client code. The VP lives in the relation
between the ...Node and the operation classes. It Encapsulates What
Varies and helps to uphold the Open/Closed Principle, because to add new
operations one does not need to touch the ...Node classes. It implements
double dispatching in a single dispatch language.


Regards,
Mick.
From: Mark Lawrence on
On 17/07/2010 20:38, Mick Krippendorf wrote:
> Karsten Wutzke wrote:
>> The visitor pattern uses single-dispatch, that is, it determines
>> which method to call be the type of object passed in.
>
> Say, in Python, I have an object o and want to call one of it's methods,
> say m. Then which of possibly many methods m to call is determined by
> the type of o, and nothing else (at least without further magic) -
> hence, it is single dispatch. The VP uses two single dispatch calls (one
> being a callback) to accomplish double dispatching.
>
> Java has a form of multiple dispatch through function overloading. In
> fact, it's still single dispatch, because which of the targets
> overloaded methods gets called is determined at compile time by the
> staticly known types of the methods parameters, AKA the formal parameter
> types.
>
> Anyway. Although VP *uses* double dispatch, it does not necessarily rely
> on function overloading. In Java the VP is most often implemented like this:
>
> <java>
>
> interface IASTNode {
> void accept(IASTVisitor);
> }
>
> class IfNode implements IASTNode {
> void accept(IASTVisitor visitor) {
> visitor.visit(this);
> }
> }
>
> class ElseNode implements IASTNode {
> void accept(IASTVisitor visitor) {
> visitor.visit(this);
> }
> }
>
> interface IASTVisitor {
> void visit(IfNode node);
> void visit(ElseNode node);
> ...
> }
> class PrettyPrinter implements IASTVisitor {
> public void visit(IfNode n) {
> ...
> }
> public void visit(ElseNode n) {
> ...
> }
> }
>
> </java>
>
> but it could as well be implemented like this:
>
> <java>
>
> interface IASTNode {
> void accept(IASTVisitor);
> }
>
> class IfNode implements IASTNode {
> void accept(IASTVisitor visitor) {
> visitor.visitIfNode(this);
> }
> }
>
> class ElseNode implements IASTNode {
> void accept(IASTVisitor visitor) {
> visitor.visitElseNode(this);
> }
> }
>
> interface IASTVisitor {
> void visitIfNode(IfNode node);
> void visitElseNode(ElseNode node);
> ...
> }
> class PrettyPrinter implements IASTVisitor {
> public void visitIfNode(IfNode n) {
> ...
> }
> public void visitElseNode(ElseNode n) {
> ...
> }
> }
>
> </java>
>
> If Java were *really* a multiple dispatch language, it wouldn't be
> necessary to repeat the accept-code for every subclass. Instead a single
> accept method in the base class would suffice. In fact, with true
> multiple dispatch VP wouldn't even be needed.
>
>
> Regards,
> Mick.

Boilerplate, boilerplate everywhere, but not a beer to drink.

Hope everyone at EuroPython is having a good time.

Kindest regards.

Mark Lawrence.

From: Mick Krippendorf on
Mark Lawrence wrote:
> On 17/07/2010 20:38, Mick Krippendorf wrote:
>>
>> If Java were *really* a multiple dispatch language, it wouldn't be
>> necessary to repeat the accept-code for every subclass. Instead a single
>> accept method in the base class would suffice. In fact, with true
>> multiple dispatch VP wouldn't even be needed.
>
> Boilerplate, boilerplate everywhere, but not a beer to drink.

That's Java for ya.

<python>

class ASTNode:
def accept(self, visitor):
getattr(visitor, self.__class__.__name__)(self)

class IfNode(ASTNode):
... # inherits generic accept method

class ElseNode(ASTNode):
... # inherits generic accept method

class PrettyPrinter:
def IfNode(self, node):
...
def ElseNode(self, node):
...

</python>

Regards,
Mick.