Slightly OT: generics problem

Hi all,

I'm going to use a slight problem I've found with IDEA to ask an OT question about generics in case anyone can help :)

I have something like the hierarchy in the attached file - I couldn't paste it here, sorry, I couldn't figure out how to make the forums format it correctly. It's a hierarchy for creating graphs - there's a series of related interfaces (Nodes have Ports, which connect them to Edges). There are various different classes of Nodes (BaseNode in this example) and each class has various specific types (SpecificNode). A given graph will only have a particular class of node, but will have many specific types (all derived from BaseNode, for example). I wanted to type the hierarchy so that the code for SpecificNode will get back a list of Port when it calls getPorts, for example. To do this I had to type all the interfaces as shown. Edge is not typed (since it goes between two nodes of different types), but the getFrom method allows the caller to specify the type it expects, I'm happy with a couple of unchecked warnings in the Edge class. This all works swimmingly until you start trying to use these collections in a generic way. The code shown appears as correct in IDEA but the compiler chokes: GenericsTest.java:23: inconvertible types found : GenericsTest.Port> required: GenericsTest.Port return (Port) fromPort; GenericsTest.java:58: incompatible types found : GenericsTest.Node required: GenericsTest.BaseNode> BaseNode>]]> baseNode = from.getNode();

Any idea why IntelliJ is not picking up this error while I edit? I've also found it's not very clever about completing type parameters, I can't use Ctrl Shift Space to get a list of potential matches, either with or without a wildcard restriction. And any clever suggestions about how I might redesign the hierarchy to allow me type safety but not be endlessly fighting with the compiler? I'm just about ready to take out all my changes and just cast everywhere.

Thanks in advance,
Colin



Attachment(s):
GenericsTest.java
7 comments

I haven't looked in detail at your code, but the Sun compiler has some
bugs dealing with parametrised types with recursive bounds. See, e.g.
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6548436
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6507317
If you are very sure that your code is correct - and Idea agrees with
you, so that's a good sign ;) - you can work around the line that
"should" compile by casting to a superclass, e.g. Object, first:
return (Port]]>) (Object) fromPort;

I'm pretty sure that's what you're running up against for the first
error, for the second it looks like a more straightforward type error
that Idea isn't picking up (from.getNode doesn't indeed give you back a
BaseNode).

R

0

Colin,
I guess I can answer your question:) Both of these errors are really javac errors,
in the first case the type are clearly convertilble. In the second case the types are assignable. One just has to pack captured wildcard back.

Eugene.

0

Wow, thanks guys, at least I know I'm not going crazy. Eugene, what do you mean by "One just has to pack captured wildcard back."?

0

Oops, sorry for this. It is just a standard type theory terminology about existential types which wildcards essentially are. when you assign List to List>]]> you "pack", when capture conversion is applied you "unpack".

0

Hmm, this seems to work sometimes, but not always. Edge.getFrom returns Port<? extends Node<?>>. The following works:

Port<? extends Node<?>> port = edge.getFrom();
BaseNode<?> baseNode = (BaseNode<?>) (Object) port.getNode();

But I can't do this:

Port<? extends BaseNode<?>> port = (Port<? extends BaseNode<?>>) (Object) edge.getFrom();
BaseNode<?> baseNode = (BaseNode<?>) (Object) port.getNode();

Should I even be able to? I think so, but today has broken my brain. I'm not sure if this is the aforementioned bug or something unrelated related to captures.

There's another thing - in the second example, IDEA highlights the whole expression (Port<? extends BaseNode<?>>) (Object) edge.getFrom() with the unchecked cast warning. But if I mouse over the first part of the expression, it also gives me a "cast to incompatible interface" warning - but only sometimes. Either way, IDEA thinks it's good and javac chokes.

0

Who knows? As soon as I see errors with words like "capture" or
"inferred type" my brain starts leaking out my ears. Unfortunately my
education focused on transistor design and thermodynamics rather than
type theory ...
You are not alone!
R

0

:) tell me about it. This afternoon I saw the weirdest error I've ever seen from javac - I wish I'd written it down for posterity. I'm starting to get a handle on the subtleties of generics, but it always seems to be a lot harder than it needs to be.

Thanks for the help, anyway! For some reason I can't give you the helpful/correct points, sorry... the prize goes to Eugene.

0

Please sign in to leave a comment.