tags:

views:

102

answers:

5

Suppose I have:

public interface Action<S extends Shape> {
  public void start( S shape );
}

Why do I get the following?

public <S extends Shape> void performAction( Action<S> action, Shape shape ) {
  action.start(shape);  // error: cannot supply Shape
}

In other words, in the future, I might have subclasses of Shape and Actions that operate on them like:

Action<Rectangle>
Action<Blob>

I'd like to have a uniform interface that can apply Actions to a bunch of different subclasses of Shape.

+4  A: 

I think you need something like this:

public <S extends Shape> void performAction(Action<S> action, S shape) {
     action.start(shape);
}

However in this case it not clear what value there is in using generics if all you are interested in is Shape and its subclasses. The code below would accomplish the same thing.

public interface Action {
    public void start(Shape someShape);
}

public void performAction(Action action, Shape someShape) {
    action.start(someShape); 
}

If however the Action class is completely generic and can be used with objects other than Shape and its subclasses then you could do the following:

public interface Action<S> {
    public void start(S target);
}

public <S> void performAction(Action<S> action, S target) {
    action.start(target);
}
Tendayi Mawushe
+1. In the original code, there was no guarantee that `shape` was of whatever type `action` was expecting.
Adam Paynter
In this case, I think generics just over complicates things.
jjnguy
@jjnguy, Agreed generics do seem unnecessary in this simple case.
Tendayi Mawushe
+1  A: 

The signature of start requires an S, but you are passing it a Shape.

danben
+1  A: 

Because the action is for a specialization of shape, not any shape.

Tom
+3  A: 

I don't think you necessarily need generics in this case. Here is what I would do:

public interface Action {
  public void start( Shape someShape );
}

public void performAction( Action action, Shape someShape ) {
  action.start(someShape); 
}

Then you can pass any type that extends Shape into the method start().

jjnguy
But suppose the Action needs to make use of some method in a subclass of Shape, i.e. like getWidth() method for a Rectangle. In this case, running an Action meant for a rectangle on a Shape object will require casting, and is no longer generally safe. What to do?
Jake
If that were the case, give Shape a method called `getWidth()` and properly override it in all the subclasses.
jjnguy
@Jake See directly above comment.
jjnguy
+1  A: 

For a basic need, I suggest:

public interface Action {
  public void start(Shape shape );
}

Or if you need to type them stronger, you could change the other:

public <S extends Shape> void performAction( Action<S> action, S shape ) {
  action.start(shape); 
}
KLE