views:

104

answers:

2

My question is not easy to explain using words, fortunately it's not too difficult to demonstrate. So, bear with me:

public interface Command<R>
{
    public R execute();//parameter R is the type of object that will be returned as the result of the execution of this command
}

public abstract class BasicCommand<R> implements Command<R>
{
}

public interface CommandProcessor<C extends Command<?>>
{
    public <R> R process(C<R> command);//this is my question... it's illegal to do, but you understand the idea behind it, right?
}

//constrain BasicCommandProcessor to commands that subclass BasicCommand
public class BasicCommandProcessor<C extends BasicCommand<?>> implements CommandProcessor<C>
{
    //here, only subclasses of BasicCommand should be allowed as arguments but these
    //BasicCommand object should be parameterized by R, like so: BasicCommand<R>
    //so the method signature should really be 
    //    public <R> R process(BasicCommand<R> command)
    //which would break the inheritance if the interface's method signature was instead:
    //    public <R> R process(Command<R> command);
    //I really hope this fully illustrates my conundrum
    public <R> R process(C<R> command)
    {
        return command.execute();
    }
}

public class CommandContext
{
    public static void main(String... args)
    {
        BasicCommandProcessor<BasicCommand<?>> bcp = new BasicCommandProcessor<BasicCommand<?>>();
        String textResult = bcp.execute(new BasicCommand<String>()
        {
            public String execute()
            {
                return "result";
            }
        });
        Long numericResult = bcp.execute(new BasicCommand<Long>()
        {
            public Long execute()
            {
                return 123L;
            }
        });
    }
}

Basically, I want the generic "process" method to dictate the type of generic parameter of the Command object. The goal is to be able to restrict different implementations of CommandProcessor to certain classes that implement Command interface and at the same time to able to call the process method of any class that implements the CommandProcessor interface and have it return the object of type specified by the parametarized Command object. I'm not sure if my explanation is clear enough, so please let me know if further explanation is needed. I guess, the question is "Would this be possible to do, at all?" If the answer is "No" what would be the best work-around (I thought of a couple on my own, but I'd like some fresh ideas)

+3  A: 

Unfortunately, you cannot do this. Since you want the CommandProcessor interface to be defined in terms of Command, your implemnetation must be prepared to take any kind of Command instance - generics cannot restrict this to BasicCommand - if it could, then the BasicCommandProcessor subclass would not implement the CommandProcessor interface.

Or, from another angle, given a CommandProcessor interface, it's not possible for generics to ensure that this was only called with BasicCommand instances. To do this would need to know the implemnetation, and would go against the point of polymorphism and interfaces.

You can parameterize the result of the command, but not the concrete class of command.

public interface Command<R>
{
    public R execute();//parameter R is the type of object that will be returned as the result of the execution of this command
}

public abstract class BasicCommand<R> implements Command<R>
{
}

public interface CommandProcessor
{
    public <R> R process(Command<R> command);
}

public class BasicCommandProcessor implements CommandProcessor
{
    public <R> R processBasicCommand(BasicCommand<R> command)
    {
       return command.execute();
    }

    public <R> R process(Command<R> command)
    {
       return processBasicCommand((BasicCommand<R>)command);
    }
}

The simplest approach is to provide a method that accepts the specific type you need, and call that in the generic method. (See BasicCommandProcessor above.)

mdma
"... given a CommandProcessor interface, it's not possible for generics to ensure that this was only called with BasicCommand instances. To do this would need to know the implemnetation, and would go against the point of polymorphism and interfaces." Of course it is. If the implementation is specified as type parameter, a subclass may further restrict the type bound, see my answer for an example. Yes, this means that the raw types do not conform to the substitution principle, and the compiler is required to emit a synthetic method to cast the method argument. But it is valid Java.
meriton
I see what you are saying. It can be made to work by adding additional parameter types for the implementation details, but to me that detracts from the point of having an interface. In my experience, it can also become unwieldy to work with as the number of interfaces grows.
mdma
It depends on the intent. If the CommandProcessor can work with all kinds of commands having the command type in the interface is indeed useless. However, if a CommandProcessor can only work with certain types of commands (as seems the case here), expressing that in the interface can be appropriate. (See "Do generics help designing parallel class hierarchies?" at http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html)
meriton
+1  A: 

Basically, I want the generic "process" method to dictate the type of generic parameter of the Command object.

This is at odds with the notion of defining the command as type parameter to the enclosing type: When instantiating a CommandProcessor, an actual type such as Command<String> could be supplied for C. It would even be possible to supply a non-generic type such as

class Foo implements Command<String> {
    ...
}

What would the meaning of C<R> be, then? Foo<R>? Command<String><R>? Command<R>?

So what options do you have? If a CommandProcessor only need to work with a specific return type, you can do:

class CommandProcessor<R, C extends Command<R>> {
    R process(C command);
}

class FancyCommandProcessor<R, C extends FancyCommand<R>> extends CommandProcessor<R,C> {

}

However, I suspect you want a CommandProcessor to work with entire type family of commands. This in itself would be no problem, simply declare:

<R> R process(FancyCommand<R> command);

If however, you additionally want a subtype relationship between CommandProcessors for different families of commands so you can override process, you venture beyond the expressiveness of Java generics. Specifically, you'd need either the equivalent of C++ 'template' type parameters (which allow to pass a template as actual type argument), or the capability to capture the type parameter of Command given an actual type argument that is known to extend Command. Java supports neither.

meriton
"That is, when instantiating a CommandProcessor, an actual type such as Command<String> must be supplied for C"Actually, you're wrong. A [wild card](http://java.sun.com/docs/books/tutorial/extra/generics/wildcards.html) (Command<?>) can always be supplied...
Andrey
I stand corrected and have edited accordingly. However, it changes little in my argument...
meriton
You've described the problem well. The only thing is the CommandProcessor doesn't actually need to know about the return type of the Command it might deal with EXCEPT for when it comes to processing them in which case it just needs to pass on the object of the type with which the Command was parameterized which isn't possible to do it seems. Upvote you back up.
Andrey