Ok, thanks Kay (and George in a private thread). it sounds to me like we only really need to specify the AST type (which can default to object when we don't care...hmm...can Java do that?) and token type. token type is fine as an interface; no point in parameterizing, unless there's some optimization that the compiler will find when we use more concrete types but it seems to work okay now
So, the AST type is really the only thing we need to given as a parameter. We need to give it to the parser, the treenode stream, tree adapter, and whatever fanout we get from that. I don't think we need to specify the payload type. I've never needed anything other than a token payload and people can simply subclass BaseTree to make their own type. all the typecasting goes away when they specify their concrete type to the parser and node stream etc. as you say, "the ASTLabelType and TokenLabelType simply become the type parameters of the extends clause". cool. Ter On Feb 7, 2010, at 4:41 AM, Kay Röpke wrote: > Hi! > > On Feb 6, 2010, at 10:32 PM, Terence Parr wrote: > >> Hi. Can someone enlighten me on the relationship between interfaces and >> generics? As it pertains to ANTLR, we have a Tree interface, but that is >> just to define some common functionality. people can define their own >> adapters and I assume only that a node is an object. Then, to get some work >> done I created CommonTree which is a subclass of BaseTree it has a token >> payload. BaseTree implements Tree. >> >> Part of me thinks that I only need a single CommonTree class now but with a >> generic parameter T that specifies the payload type. Unfortunately that >> doesn't solve some of my use cases where I hate having to use typecasts. If >> I create my own adapter that specifies how to create types, it might return >> FooNode objects. Every time I ask for CommonTree<Token>.getChild(3), I have >> to cast it to FooNode. Does that mean we need another parameter on the >> tree? CommonTree<PayloadType, NodeType>? seems weird. > > Yes, it does seem weird. I wonder why CommonTree would need to be > parameterized with the NodeType, isn't CommonTree already the concrete type? > To me it sounds like the TreeAdaptor would be TreeAdaptor<NodeType, > PayloadType>, and then: > CommonTreeAdaptor implements TreeAdaptor<CommonTree, CommonToken> { … } > > All the methods/fields in CommonTreeAdaptor then would have concrete types > (likewise for any custom tree adaptor a user declares). > > That, however, poses another problem in the "generic" recognizer classes (I > really shouldn't use the word generic in this context, but can't of another > word right now). > >> Do we need the interface anymore given that we have generics? what about >> backward compatibility? maybe I should leave the existing hierarchy alone >> and create a new generic treenode that accepts the appropriate generic types? > > I would probably not shoot for backwards compatibility with this. Maybe it's > possible to support, but I wouldn't bet on it, and frankly, there are likely > too many changes anyway to be compatible at this point. Also, the > incompatible parts should be constrained to a small part of any users' code, > so it should be ok. > As to whether we need the interface, I'm not sure. Part of me thinks that > having the interface would at least make it more obvious what's going on, but > it's probably not strictly necessary. > >> For some reason it's not obvious to me how to use generics in this case. can >> someone with more experience, gives me their thoughts? > > I'm not entirely sure which use case is giving you a headache, could you > paste (or point to) an example? > >> Ter >> PS seems like we want to generate a generic parser/lexer/treeparser >> blackbox with two primary parameters Token and Tree generic types. > > Yes, the main problem with generics in this context is the following ugly > wart: > In the abstract parser superclass you will somehow have to refer to a > TreeAdaptor<?, ?> (in which the ?, ? are <CommonTree, CommonToken > for > CommonTreeAdaptor). > Since that's not feasible, because you would have to use typecasts all over > again (you can't do much with wildcard types at all…) please see the > following mock definitions: > > CommonTree: always uses CommonToken > > public class CommonTree extends BaseTree { > CommonToken token; > ... > } > > CommonTreeAdaptor defined in terms of the generic TreeAdaptor interface. > Like the definition before, just that each reference to Object is now > CommonTree and Token is CommonToken (although that's not a requirement, could > be Token instead). > > public class CommonTreeAdaptor implements TreeAdaptor<CommonTree, > CommonToken> { > @Override public CommonTree create(CommonToken payload) { ... } > } > > TreeAdaptor is as such: > > public interface TreeAdaptor<TreeType, PayloadType> { > public TreeType create(PayloadType payload); > ... > } > > The "generic parser" (in the real thing derived from BaseRecognizer, omitted > for brevity here): > > public abstract class Parser<NodeType, PayloadType> { > > private TreeAdaptor<NodeType, PayloadType> adaptor; > > public void setAdaptor(TreeAdaptor<NodeType, PayloadType> adaptor) { > this.adaptor = adaptor; > } > > public TreeAdaptor<NodeType, PayloadType> getAdaptor() { > return adaptor; > } > > /* Note: actual types! */ > public void example() { > NodeType create = adaptor.create(-1, "EOF"); > NodeType dup = adaptor.dupNode(create); > } > } > > Ok, those are the things that work today. Now let's create a custom node type > and an adaptor for it: > > // lame, it's actually empty and just an Object subclass > public class CustomNodeType { > > } > > public class CustomNodeAdaptor implements TreeAdaptor<CustomNodeType, > CommonToken> { > @Override public CustomNodeType create(CommonToken payload) { ... } > } > > That's the runtime part of it. Now let's look at how we generate recognizers > that use actual types and no casts whatsoever. They derive from abstract > Parser<NodeType, PayloadType>: > > First the "common case": > public class CommonParser extends Parser<CommonTree, CommonToken> { > > public CommonTree a() { > CommonTree a_result; > CommonToken someToken = input.match(1); // also generic > tokenstream, would return a CommonToken > a_result = getAdaptor().create(someToken); > return a_result; > } > } > > The "custom node" version: > public class TestParser extends Parser<CustomNodeType, CommonToken> { > > public CustomNodeType a() { > CustomNodeType a_result; > CommonToken someToken = input.match(1); // also generic > tokenstream, would return a CommonToken > a_result = getAdaptor().create(someToken); > return a_result; > } > } > > Note how the ASTLabelType and TokenLabelType simply become the type > parameters of the extends clause (and of course everywhere as variable types, > method return types etc). > And, most importantly, type safe, no casts, easy to read. > > Here's a mock Main.java: > public class Main { > > public static void main(String[] args) { > TestParser parser = new TestParser(); > parser.setAdaptor(new CustomNodeAdaptor()); > CustomNodeType customNode = parser.a(); > > CommonParser cp = new CommonParser(); > cp.setAdaptor(new CommonTreeAdaptor()); > CommonTree ct = cp.a(); > } > } > > Again, no casts. Neat, if you ask me. > There's on problem with the two becomeRoot() methods in the TreeAdaptor > interface. > One is > public abstract TreeType becomeRoot(TreeType newRoot, TreeType oldRoot); > the other: > public abstract TreeType becomeRoot(PayloadType newRoot, TreeType > oldRoot); > > Because of type erasure they end up having the same signature, so the > convenience one should be renamed, IMHO. Not a big deal. > > Let me know if the above wasn't clear enough, it got a bit out of hand > length-wise :) > > BTW, it won't even compile if you try to do: > parser.setAdaptor(new CommonTreeAdaptor()); > since it does not support the correct ASTLabelType. No more unpleasant > runtime ClassCastExceptions here :) > > cheers, > -k > _______________________________________________ > antlr-dev mailing list > antlr-dev@antlr.org > http://www.antlr.org/mailman/listinfo/antlr-dev _______________________________________________ antlr-dev mailing list antlr-dev@antlr.org http://www.antlr.org/mailman/listinfo/antlr-dev