23

I would like my BallUserInterfaceFactory to return an instance of a user interface that has the proper generic type. I am stuck in the example below getting the error:

Bound mismatch: The generic method getBaseballUserInterface(BASEBALL) of type BallUserInterfaceFactory is not applicable for the arguments (BALL). The inferred type BALL is not a valid substitute for the bounded parameter

public class BallUserInterfaceFactory {
    public static <BALL extends Ball> BallUserInterface<BALL> getUserInterface(BALL ball) {

        if(ball instanceof Baseball){
            return getBaseballUserInterface(ball);
        }
        //Other ball types go here

        //Unable to create a UI for ball
        return null;
    }

    private static <BASEBALL extends Baseball> BaseballUserInterface<BASEBALL> getBaseballUserInterface(BASEBALL ball){
        return new BaseballUserInterface<BASEBALL>(ball);
    }
}

I understand that it cannot guarantee that BALL is a Baseball, and so there is a parameter type mismatch on the getBaseballUserInterface method call.

If I cast the ball parameter in the getBaseballUserInterface method call, then I get the error:

Type mismatch: cannot convert from BaseballUserInterface<Baseball> to BallUserInterface<BALL>

Because it can't guarantee that what I am returning is the same type of BALL.

My question is, what is the strategy for dealing with this situation?

(For completeness, here are the other classes required in the example)

public class Ball {

}

public class Baseball extends Ball {

}

public class BallUserInterface <BALL extends Ball> {

    private BALL ball;

    public BallUserInterface(BALL ball){
        this.ball = ball;
    }
}

public class BaseballUserInterface<BASEBALL extends Baseball> extends BallUserInterface<BASEBALL>{

    public BaseballUserInterface(BASEBALL ball) {
        super(ball);
    }

}
Amr ElAdawy
  • 3,663
  • 5
  • 31
  • 48
FuryComputers
  • 866
  • 1
  • 12
  • 23
  • Is BaseballUserInterface extends BallUserInterface not enough? Do you have Subclasses of BaseballUserInterface? – ollins Sep 27 '12 at 19:34
  • @ollins I was using that strategy originally, if you change the example to that, you will end up with another "Type mismatch" situation because there is no guarantee that the BALL type returned from the factory is the same as the BALL type in the BallUserInterface. (This time specified in the BaseballUserInterface class declaration). – FuryComputers Sep 27 '12 at 20:04

3 Answers3

21

This is a wrong design pattern. Rather than using one generic method and an if ladder, you should instead use overloading. Overloading eliminates the need for the if ladder and the compiler can make sure the correct method is invoked rather than having to wait till runtime.

eg.

public class BallUserInterfaceFactory {

    public static BallUserInterface<Baseball> getUserInterface(
            Baseball ball) {
        return new BallUserInterface<Baseball>(ball);
    }

    public static BallUserInterface<Football> getUserInterface(
            Football ball) {
        return new BallUserInterface<Football>(ball);
    }
}

This way you also get the added benefit of compile time errors if your code cannot create a BallUserInterface for the appropriate ball.


To avoid the if ladder you can use a technique known as double dispatch. In essence, we use the fact that the instance knows what class it belongs to and calls the appropriate factory method for us. For this to work Ball needs to have a method that returns the appropriate BallInterface.

You can either make the method abstract or provide a default implementation that throws an exception or returns null. Ball and Baseball should now look something like:

public abstract class Ball<T extends Ball<T>> {
    abstract BallUserInterface<T> getBallUserInterface();
}

.

public class Baseball extends Ball<Baseball> {
    @Override
    BallUserInterface<Baseball> getBallUserInterface() {
        return BallUserInterfaceFactory.getUserInterface(this);
    }
}

To make things a little neater, it's better to make getBallUserInterface package private and provide a generic getter in BallUserInterfaceFactory. The factory can then manage additional checks like for null and any thrown exceptions. eg.

public class BallUserInterfaceFactory { 
    public static BallUserInterface<Baseball> getUserInterface(
            Baseball ball) {
        return new BallUserInterface<Baseball>(ball);
    }   
    public static <T extends Ball<T>> BallUserInterface<T> getUserInterface(
            T ball) {
        return ball.getBallUserInterface();
    }
}

The Visitor Pattern

As pointed out in the comments, one problem of the above is it requires the Ball classes to have knowledge of the UI, which is highly undesirable. You can, however, use the visitor pattern, which enables you to use double dispatch, but also decouples the various Ball classes and the UI.

First, the necessary visitor classes, and factory functions:

public interface Visitor<T> {
    public T visit(Baseball ball);
    public T visit(Football ball);
}

public class BallUserInterfaceVisitor implements Visitor<BallUserInterface<? extends Ball>> {
    @Override
    public BallUserInterface<Baseball> visit(Baseball ball) {
        // Since we now know the ball type, we can call the appropriate factory function
        return BallUserInterfaceFactory.getUserInterface(ball);
    }   
    @Override
    public BallUserInterface<Football> visit(Football ball) {
        return BallUserInterfaceFactory.getUserInterface(ball);
    }
}

public class BallUserInterfaceFactory {
    public static BallUserInterface<? extends Ball> getUserInterface(Ball ball) {
        return ball.accept(new BallUserInterfaceVisitor());
    }
    // other factory functions for when concrete ball type is known
}

You'll note that the visitor and the factory function have to use wildcards. This is necessary for type safety. Since you don't know what type of ball has been passed, the method cannot be sure of what UI is being returned (other than it is a ball UI).

Secondly, you need to define an abstract accept method on Ball that accepts a Visitor. Each concrete implementation of Ball must also implement this method for the visitor pattern to work correctly. The implementation looks exactly the same, but the type system ensures dispatch of the appropriate methods.

public interface Ball {
    public <T> T accept(Visitor<T> visitor);
}

public class Baseball implements Ball {
    @Override
    public <T> T accept(Visitor<T> visitor) {
        return visitor.visit(this);
    }
}

Finally, a bit of code that can put all this together:

Ball baseball = new Baseball();
Ball football = new Football();

List<BallUserInterface<? extends Ball>> uiList = new ArrayList<>();

uiList.add(BallUserInterfaceFactory.getUserInterface(baseball));
uiList.add(BallUserInterfaceFactory.getUserInterface(football));

for (BallUserInterface<? extends Ball> ui : uiList) {
    System.out.println(ui);
}

// Outputs:
// ui.BaseballUserInterface@37e247e2
// ui.FootballUserInterface@1f2f0ce9
Amr ElAdawy
  • 3,663
  • 5
  • 31
  • 48
Dunes
  • 32,114
  • 7
  • 68
  • 83
  • 1
    I really like this answer, but here is the issue I have with it: If I have a Ball then I cant call getUserInterface without putting an if ladder somewhere else. For instance: `Ball ball = new Baseball(); BallUserInterface> ui = BallUserInterfaceFactory.getUserInterface(ball);` Does not work because there could be other types of Ball that are not overloaded in the factory method. – FuryComputers Sep 28 '12 at 14:08
  • @FuryComptuers But if you only have a `Ball`, you don't need the additional information a generic method will give you. You can just receive `BallUserInterface>`. – artbristol Oct 01 '12 at 08:56
  • 2
    I added a bit about using double dispatch to avoid if ladders. – Dunes Oct 01 '12 at 09:35
  • 3
    An object should not have any information about its User Interface, so adding a UI return method to the object is not the correct solution. – HeavyE Oct 01 '12 at 16:34
  • I should also add that it isn't even reasonable to assume that someone building a UI for a Ball object has the ability to change the Ball object. (though a wrapper could be created client-side) – HeavyE Oct 01 '12 at 16:35
  • I have up voted this answer because think it may help others, but for me, it just moved the problem to other places in the code. I also agree with HeavyE that the object should not have any knowledge of it's UI. – FuryComputers Oct 11 '12 at 17:14
3

This is a VERY GOOD question.

You could cast brutely

    return (BallUserInterface<BALL>)getBaseballUserInterface((Baseball)ball);

The answer is theoretically flawed, since we force BASEBALL=Baseball.

It works due to erasure. Actually it depends on erasure.

I hope there is a better answer that is reification safe.

irreputable
  • 42,827
  • 9
  • 59
  • 89
  • IMHO that cast is safe, despite the warning. With reification, wouldn't the cast be checked at runtime and presumably always work? – artbristol Sep 28 '12 at 07:06
  • It is unfortunate, but this seems to be the only solution that doesn't move the problem somewhere else in the code. – FuryComputers Oct 11 '12 at 17:16
0
public class BaseballUserInterface extends BallUserInterface<Baseball> {

    public BaseballUserInterface(Baseball ball) {
        super(ball);
    }
}

You are using the BallUserInterface as a result of the factory method. So, it can be hidden which concrete ball is used:

public class BallUserInterfaceFactory {

public static BallUserInterface<?> getUserInterface(Ball ball) {

        if(ball instanceof Baseball){
            return getBaseballUserInterface((Baseball)ball);
        }

        return null;
    }

    private static BaseballUserInterface getBaseballUserInterface(Baseball ball){
        return new BaseballUserInterface(ball);
    }
}

If the client is interested in the type of the ball you should offer a factory method with the concrete ball as parameter:

public static BaseballUserInterface getUserInterface(Baseball ball){
    return new BaseballUserInterface(ball);
}
ollins
  • 1,791
  • 11
  • 16