1

I have a class hierarchy where cousins share very similar functionality. For example:

Node
  Statement
    FunctionCallStatement
  Expression
    FunctionCallExpression

FunctionCallStatement and FunctionCallExpression share a very similar API, but I cannot express that in pure class terms with a single-inheritance hierarchy. So, I've created an IsFunctionCall Interface which both of these implement. I can now declare a method which takes either a FunctionCallStatement or a FunctionCallExpression as follows:

void <T extends Node & IsFunctionCall> doSomething(T node) { ... }

This all works very nicely.

Unfortunately, I've now found myself faced with a rather awkward problem. I have a Node; I know dynamically that it must be either a FunctionCallStatement or a FunctionCallExpression; I need to pass that Node into the doSomething() method above. I cannot find a way to upcast it to an appropriate type.

Right now I'm using a chain of instanceof to determine which class the Node is and to cast it to the appropriate concrete type, but that's butt-ugly. The only other way I know to make this work is to make an IsNode interface and have everything that currently expects a Node expect an IsNode instead; this would allow me to declare a union interface that implements IsNode and IsFunctionCall and let me do away without the generics above. But that's a hell of a lot of work and is still pretty ugly.

Is there an alternative way to do this?

(Note: example above is a simplified version of my actual code.)

Update: I tried the following piece of evil:

@SuppressWarnings("unchecked")
private <S extends Node & IsFunctionCall> S castNode(Node node)
{
    return (S) node;
}

and then:

doSomething(castNode(node));

I got some very strange error messages. It would appear that the type inference used to determine the S of castNode() will not match against the T in the declaration of doSomething(); it's using the concrete type only and setting S to Node. Which of course does not match doSomething()'s declared type. Very peculiar.

Update update:

This appears to be a close duplicate of How should I cast for Java generic with multiple bounds?. My situation is slightly different because my bounds include an object and an interface, while the one in the other question has two interfaces, but it's still applicable.

Looks like I need to go and reengineer my entire application. Sigh.

Any admin, feel free to close this as a duplicate...

Community
  • 1
  • 1
David Given
  • 13,277
  • 9
  • 76
  • 123
  • possible duplicate of [How should I cast for Java generic with multiple bounds?](http://stackoverflow.com/questions/318208/how-should-i-cast-for-java-generic-with-multiple-bounds) – David Given Feb 20 '12 at 14:17

2 Answers2

0

I think the way out of this, although not exactly elegant, is to have a few overloads for doSomething:

void doSomething(FunctionCallStatement node) ...
void doSomething(FunctionCallExpression node) ...
zmbq
  • 38,013
  • 14
  • 101
  • 171
0

You are using the interface to flag functionality, how about passing as argument a reference to the FunctionCallInterface which offers access to the function call abstraction?

doSomething won't have to know the actual implementation type as long as it can access the relevant information and call relevant methods on the implementation objects.

public class FunctionCallStatement extends Statement implements FunctionCallInterface {
}

void doSomething(FunctionCallInterface node) {
}
rsp
  • 23,135
  • 6
  • 55
  • 69
  • `doSomething()` needs to access Node functionality as well as FunctionCallInterface functionality, hence the reason for the generic type. I suppose I could pass in a Node *and* a FunctionCallInterface, although they will both end up being the same object... – David Given Feb 19 '12 at 13:24
  • @David Given, you could define a `NodeInterface` which `Node` implements and let the `FunctionCallInterface` extend that so that it supplies all functionality you need. – rsp Feb 19 '12 at 17:41