15

I have the following method:

public <T extends Result> T execute(Command<T> command)
{
     return new LoginResult();
}

Here, Result is an interface, and the class LoginResult does implement this interface. However, I'm getting the error:

Incompatible types, required: T, found: com.foo.LoginResult

Yet if I change the method signature to:

public Result execute(Command<T> command)

Then the same return line works fine, without any error.

What's the issue here? And how can I return LoginResult from this method?

Edit: The reason I want to use generics, is so I can do something like the following:

Command<LoginResult> login = new Command<>();
 LoginResult result = execute( login );
Click Upvote
  • 235,452
  • 251
  • 553
  • 736
  • 6
    Why do you want to have `````` as a return value? If you just put a ```Result``` there, it can also return subclasses. Where do you want to get the generic type from? Is the class also generic? – NeplatnyUdaj Feb 11 '14 at 14:54
  • Indeed, @NeplatnyUdaj, using generics like that only really makes sense within collections – Richard Tingle Feb 11 '14 at 14:56
  • @NeplatnyUdaj Well, my actual code signature is different than what I've shown here. I'll edit the question and update – Click Upvote Feb 11 '14 at 14:58
  • 1
    Add a `Class cls` parameter, and downcast the result using `Class.cast()`. This will get rid of the compiler error, and cause a `ClassCastException` to only occur where an actual cast is visible in the code. – millimoose Feb 11 '14 at 15:13

5 Answers5

16

You can't do this because the compiler can't confirm that LoginResult is of type T, since it's inferred at the call site (i.e. the caller decides which type parameter will be used).

Paŭlo Ebermann
  • 68,531
  • 18
  • 138
  • 203
SimonC
  • 6,382
  • 21
  • 40
  • Why not? If I change the return type to `Result`, then it does return correctly – Click Upvote Feb 11 '14 at 14:55
  • 13
    @ClickUpvote Because `` doesn't mean "any class that extends Result". It means "a specific class that extends Result, but we don't know what that class is". – Anthony Grist Feb 11 '14 at 14:56
  • This type of question is asked quite frequently. For example: http://stackoverflow.com/questions/75175/create-instance-of-generic-type-in-java – SimonC Feb 11 '14 at 14:58
  • This is the right answer. I was about to post this after seeing the accepted answer, and then saw this. +1. – Cruncher Feb 11 '14 at 20:36
  • @AnthonyGrist ... or more exactly "..., but the caller of the method decides which one". – Paŭlo Ebermann Feb 11 '14 at 22:15
  • @PaŭloEbermann Well, because of type erasure, the caller really doesn't make a decision – there's no way to communicate it to the callee. (Unless you use an explicit type token, which is a practice everyone writing generic code should be aware of.) – millimoose Feb 15 '14 at 02:11
  • 1
    @millimoose You are right: the caller decides what she wants to get back, and the callee doesn't know about it. This means you effectively only can return `null` from such a method. – Paŭlo Ebermann Feb 15 '14 at 05:19
  • @PaŭloEbermann And this is why the OP's method signature as-is is unsalvageable. – millimoose Feb 15 '14 at 23:11
6

To answer your edited question,

there's no way to do that without an explicit cast. So the simplest (yet brutal) solution would be:

public <T extends Result> T execute(Command<T> command) {
    return (T) new LoginResult();
}

But this way you take the full responsibility for instantiating the right result for the right command, as the compiler won't help you any more.

The only thing that could help you instantiate things dynamically would be a reference to the actual Class<T>.

So if you add a method like Class<T> getResultType() to your command, you would be able to write:

return command.getResultType().newInstance(); // instead of new SpecificResult()

This of course implies that you have a default constructor in each Result implementation and so on...

A more OO friendly approach (no reflection) would be to let the command instantiate its own result (with a factory method T instantiateResult()):

return command.instantiateResult();
Costi Ciudatu
  • 33,403
  • 5
  • 52
  • 89
  • Well, I'm actually using the `Class actualType` method in my real code, I've edited my question to show this. But I'm still not able to return `LoginResult` – Click Upvote Feb 11 '14 at 15:01
  • @ClickUpvote I recommend you to post a SSCCE of your real code to get a more specific analysis and solution for your problem – Luiggi Mendoza Feb 11 '14 at 15:03
  • You need to return an instance of `actualType` then. If that will always be `LoginResult`, there's nothing dynamic in it so you should stay away from generic headaches. – Costi Ciudatu Feb 11 '14 at 15:03
  • @LuiggiMendoza I think the example I put in my edit in the question should give a fairly good idea of what's happening and what i'm trying to do – Click Upvote Feb 11 '14 at 15:04
  • @ClickUpvote it is for us, but look that it's not fulfilling your expectations. So, put more info to get a more detailed and accurate answer. – Luiggi Mendoza Feb 11 '14 at 15:05
  • @CostiCiudatu No, it wouldn't always be `LoginResult`, it could be any class implementing `Result`, but it would be instantiated the same way as I'm instantiating `LoginResult` right now – Click Upvote Feb 11 '14 at 15:05
  • Don't you mean `T getResultType()` rather than `Command getResultType()` ? – Click Upvote Feb 11 '14 at 15:21
  • No, that's Class, that you can use to instantiate results. – Costi Ciudatu Feb 11 '14 at 15:24
2

Expanding on SimonC's answer a little bit.

Consider you have classes:

Result

LoginResult extends Result

OtherResult extends Result

If your type T is OtherResult then trying to return a LoginResult is nonsense. The compiler will only compile it if it can GUARANTEE sensibility at compile time. As it stands it cannot, since T can be an incompatible type with LoginResult.

A return type of <T extends Result> does NOT mean that you have to return something that is a Result. It means that you need to return something that is a T, but T has to be a subclass of Result

Regarding your edit

Edit: The reason I want to use generics, is so I can do something like the following:

Command<LoginResult> login = new Command<>();
 LoginResult result = execute( login );

I'm not sure exactly what execute should do, but my first thought is to make execute an instance method of Command.

Then you would have

public T execute()
{

}

The problem is you need a way to instantiate LoginResult. This is where we need more information into your specific problem to give a detailed answer.

I would make a static method in Result called newInstance. Then since you know T is some subclass of result you can call T.newInstance(). Then your would-be constructor for loginResult can be private, and you call it through it's newInstance method.

This requires your Command to be defined as:

public class Command<T extends Result>

And Result must have a method with signature:

public static Result newInstance()

Another concern that may arise is that you don't want to constrain Command to Results. That's fine, you can make a new class:

public class ResultCommand<T extends Result> extends Command
Community
  • 1
  • 1
Cruncher
  • 7,241
  • 1
  • 26
  • 62
1

The safer solution than an unchecked cast:

public <T extends Result> T execute(Command<T> command, Class<T> cls)
{
    return cls.cast(new LoginResult());
}

LoginResult result = execute(loginCommand, LoginResult.class);

The rationale behind having both parameters is that the contract of execute is implied to be:

  • Either use a method of Command to obtain a result of type T to return it.
  • Or create a result in some other way, but ensure it is of type T by downcasting it.

With Java's generics, only parameters to a generic method of the form <T> T foo(Bar<T>, Baz<T>) can safely "create" an object of the type T. Thus, if in your case, you're not creating the result using the command parameter, you need another parameter that can take care of the type check.

millimoose
  • 36,982
  • 8
  • 75
  • 128
  • Though in most choices of `T` this method would throw a ClassCastException. – Paŭlo Ebermann Feb 15 '14 at 05:21
  • @PaŭloEbermann With the design as-is, this is unavoidable no matter what. The idea is to throw a `ClassCastException` from a line of code that has a cast operator or a `.cast()` call on it. Different designs are possible, using the `cls` parameter in some other way – perhaps using `.newInstance()` to create a result of the appropriate type. Or using `isInstance()` to select one of several possible result objects. The fundamental idea is that the extra parameter enables you to do something else than "fail somewhere dumb." – millimoose Feb 15 '14 at 23:10
-1

The compiler needs to know the return value will match type T and it can't. It will match if you pass Command as parameter but it may not if you pass Command since T will be defined to that other type.

You can cast it at runtime and it will throw ClassCastException if the object you are returning does not match T.

public <T extends Result> T execute(Command<T> command, Class<T> type)
{

     return type.cast( new LoginResult() );
}

You would call it this way:

Command<LoginResult> login = new Command<>();
LoginResult result = execute( login, LoginResult.class );

Note the redundant information here but it is needed since generics are lost in compilation.

aalku
  • 2,720
  • 1
  • 18
  • 41
  • -1: This isn't type safe, and can lead to a ClassCastException in a confusing location. There's a very good reason why you get those unchecked cast warnings, you should only ignore them when you're *absolutely sure* the "cast" is valid. – millimoose Feb 11 '14 at 15:11
  • `NoLoginResult x = execute(commandThatReturnsNoLoginResult)` would cause a ClassCastException here – Marco13 Feb 11 '14 at 15:11
  • @millimoose Can you suggest a typesafe solution? If not, this seems like the best option to do what I'm trying to do. I can do a lot of checking before doing the cast to make sure it casts to the correct type. – Click Upvote Feb 11 '14 at 15:12
  • I didn't tell anyone to ignore the warning, I said the warning is there so you can check your code. That warning means the compiler can't check the code 'correctness' for you, you have to do all the work yourself. – aalku Feb 11 '14 at 15:16
  • 2
    @ClickUpvote Adding a `Class.cast()` is always an improvement, because then at least the exception is thrown a) from an actual cast visible in the code, not one generated by the compiler; and b) as early as possible. Even if you ignore an unchecked cast, the actual checked cast has to occur **somewhere**. Might as well fail fast and in a clear way. – millimoose Feb 11 '14 at 15:16
  • @user270349 No, the warning should by all rights be a compile-time error, but it's not because of the backwards compatibility requirement. Code with unchecked warnings is broken until proven otherwise, and you have not proven otherwise. Except in rare cases, you're not supposed to "check correctness", you're supposed to get rid of the warning. This is not one of those rare cases. (An example would be a `Map` where you want the object to be of the type of the key, where the relationship cannot be proven at compile-time, but is feasible to ensure by wrapping the map.) – millimoose Feb 11 '14 at 15:17
  • @millimoose How would I do `Class.cast`? If I try: `return T.class.cast(new LoginResult() );` I get: 'cannot select from a type variable` – Click Upvote Feb 11 '14 at 15:19
  • @ClickUpvote You pass a `Class cls` parameter to the method indicating the type you want to receive. Basically, in Java, only parameters to a generic method that are themselves generic with respect to `T` can safely "create" objects of type `T`. In your case, if you're not returning the result using some method like `T createResult()` in `Command`, you need to add another parameter capable of doing so. Since what you need here is a cast to `T`, that parameter has to be `Class`. – millimoose Feb 11 '14 at 15:20