java - Is skipping "accept" where type is known, a valid optimization for the Visitor pattern? -
consider following visitor simple language interpreter.
public interface visitor{ void visit( varstat vs); void visit( ident i); void visit( intliteral a); void visit( sum s); }
for completeness add code gives necessary implementation details (you can skip , read directly question).
public interface visitable{ void accept( visitor v); } public class varstat implements visitable{ ident i; exp e; public varstat(ident id, exp ex){ = id; e = ex; } public ident getident() { return i; } public exp getexp() { return e; } @override public void accept( visitor v){ v.visit( this); } } public interface exp extends visitable{ } public class ident implements exp{ @override public void accept( visitor v){ v.visit( this); } }
a var statement defined that:
varstat ::== var ident = exp; exp ::== exp + exp | intliteral | ident intliteral ::== [0-9]{0,8} ident ::== [a-za-z]+
a valid language instance
var x = x+y+4;
an abstract way represent varstat
node following:
. _____varstat _____ . / / | \ \ . / / | \ \ . / / | \ \ . "var" ident "=" exp ";"
the question
the usual visitorpattern application be
void visit( varstat vs){ vs.getident().accept( this); vs.getexp().accept( this); //... }
however, since know "ident" of type ident
possible optimization is
void visit( varstat vs){ visit( vs.getident()); vs.getexp().accept( this); //... }
that skip 2 method calls improving performance (actually gives nice boost in scenario).
is considered design error lead future problems?
visitor complicated scaffold implement double-dispatch on languages java.
when deal leaf types, don't need double-dispatch; runtime type known @ compile time. dispatch leaf type directly not optimization, it's more out of principle.
of course, problem is, in future, leaf type may become super type. today's refactor tool in ides, not huge problem.
it better make simple design present's requirement, make complex design unknown future requirements.
in java 8, can implement double-dispatch syntax that's close real double-dispatch
final doubledispatch<root,void> dd = new doubledispatch<>(); dd.register(x.class, x-> { x; compile time type x return null; }); dd.register(y.class, y-> { y; compile time type y return null; }); // etc ... dd.invoke( ); // ---- public class doubledispatch<t, r> { public r invoke(t obj){...} public <c extends t> void register(class<c> type, function<c,r> func){...} }
Comments
Post a Comment