Re: Please explain this polymorphism twist to me.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Lew schreef:
| Hendrik Maryns wrote:
|> -----BEGIN PGP SIGNED MESSAGE-----
|> Hash: SHA1
|>
|> Martin schreef:
|> | Hi there,
|> |
|> | I discovered a strange twist in polymorphism that leaves me in the
|> | dark. If you can figure out what the following output will be, then
|> | please explain to me why.
|>
|> <snip>
|>
|> | "Visitor.visit(Super)"
|> | That means, the call "visitor.visit(this);" in the type Super is
|> | handled by "Visitor.visit(Super)" instead of "Visitor.visit(Sub)".
|> | This occurs as especially strange to me because a look in the debugger
|> | confirms that the actual (dynamic) type of "this" is Sub! In my
|> | opinion, the call should therefore be dynamically handled by
|> | "Visitor.visit(Sub)".
|> |
|> | I hope I didn't confuse you with Super-Sub, now, and you can tell me
|> | where I need to review the JLS to turn on my light again.
|>
|> Yes, I stepped into this trap once as well. You need to override
|> accept(Visitor) in each subclass. Others have explained well why this
|> is so.
|>
|> The proper thing to do would be: do not use overloading, then you
|> wouldn2"t have thought of this!
|>
|> So: (note the names in Visitor)
|>
|> public class OverloadTest {
|>
|> ~ public class Visitor {
|> public void visitSuper(Super s) {
|> System.out.println("Visitor.visit(Super)");
|> }
|>
|> public void visitSub(Sub s) {
|> System.out.println("Visitor.visit(Sub)");
|> }
|> ~ }
|>
|> ~ public class Super {
|> public void accept(Visitor visitor) {
|> visitor.visitSuper(this);
|> }
|> ~ }
|>
|> ~ public class Sub extends Super {
|> public void accept(Visitor visitor) {
|> visitor.visitSub(this);
|> }
|> ~ }
|>
|> ~ public static void main(String[] args) {
|> OverloadTest o = new OverloadTest();
|> Sub s = o.new Sub();
|> s.accept(o.new Visitor());
|> ~ }
|> }
|>
|> Overloading is not always considered a good thing in programming
|> languages, and this is one of the reasons why. One can do without
|> easily.
|
| But it isn't as bad as unnecessary coupling. Isn't the point of the
| Visitor pattern that the Visitor knows nothing about the classes that it
| visits? Now Sub and Super both depend on Visitor, and Visitor depends
| on both Sub and Super. That's a circular dependency, and it's a Very
| Bad Thing. There's nothing wrong with overloading methods; it's one of
| the seminal idioms of object-oriented programming and Java in particular.
|
| Good example of an antipattern to avoid, though.
Then how would you implement this, if I may ask?
Ok, there2"s several flavors of visitors. I was thinking about a visitor
which knows what it is visiting, i.e. a visitor which does the
recursion/navigation itself. What2"s the difference between visit(Sub
sub) and visitSub(Sub sub)? Nothing, except the name. And I don2"t see
how you can do without.
Also, a Visitable will always accept a certain type of visitor, so it
will also know its interface. Then why not have it call the proper
method from the start.
I see the circular dependency, but I think it is inherent in the visitor
pattern.
H.
- --
Hendrik Maryns
http://tcl.sfs.uni-tuebingen.de/~hendrik/
==================
http://aouw.org
Ask smart questions, get good answers:
http://www.catb.org/~esr/faqs/smart-questions.html
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.4-svn0 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org
iD8DBQFIEdtre+7xMGD3itQRAhhaAJ9/3rlBSpNZDiXf0K5v4cR0AZ6+rQCfSVgj
/8Uga/M9WE7XwqmZbT8w+yc=
=utvL
-----END PGP SIGNATURE-----