4

I have a method submit:

<T> Future<Optional<T>> submit(Value<T> value) {
    //...
}

and a call of this method.

Value<?> value = null;
Future<Optional<?>> future = submit(value);

But it does not compile unless I change the signature to Future<? extends Optional<?>> future because submit returns Future<Optional<caputure of ?>> which is not Future<Optional<?>> since generics are invariant. Is there any way to give a hint to a compiler and call the method submit so it returns Future<Optional<?>>?

This snippet

<T, E extends Future<Optional<T>>> E submit(Value<T> value) {
  // ...
}
Value<?> value = null;
Future<Optional<?>> future = submit(value);

compiles as well but then I need to do unsafe cast to E before returning the value.

Here is an answer explaining the generics invariance but it still does not answer how to work with captured types.

Multiple wildcards on a generic methods makes Java compiler (and me!) very confused

Community
  • 1
  • 1
Nutel
  • 2,244
  • 2
  • 27
  • 50
  • Why is this a problem? As far as I can see there's no practical difference, `future.get()` will return an `Optional>` object. – biziclop Jul 24 '14 at 14:53

4 Answers4

2

Although I'm not sure why using it as Future<? extends Optional<?>> should be a problem, there may be a solution, depending on how many contortions and "tricks" you are willing to accept.

It is not possible to compile it in the desired form, even when using the additonal type parameter E, simply because it is not type safe. At least, it is not possible (for the compiler) to make sure that it is type safe. The reason why it could not be type safe can be summarized as follows: Someone receiving the Future<Optional<?>> could modify the Future, and assign it any Optional - even one that has a different type than the one that it was originally created with. At a different location, someone could know the Future with its original type, and receive a ClassCastException when trying to use it. (I explained this with a simpler example in https://stackoverflow.com/a/22193221/3182664 )

But...

... all this is not relevant here. The Future interface does not allow to "set" any new value. Thus, it is perfectly feasible to convert it into a Future with a supertype of its original type.

Note: This is similar to the fact that you can write

List<Integer> integers = new ArrayList<Integer>();
List<Number> numbers = Collections.unmodifiableList(integers);

This is valid (meaning "type safe") because you can not pollute the Integer-list with invalid Number instances (like Doubles), because it's not possible to modify the list anyhow!

So one type-safe, warning-free and valid solution could be to introduce a method that "wraps" a Future<? extends T> and returns it as a Future<T>. Again: This is not really pretty, and may not be worth the effort, but at least one option:

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class GenericOptionalFutureMethod
{
    void call()
    {
        Value<?> value = null;
        Future<Optional<?>> future = 
            FutureWrapper.<Optional<?>>wrap(submit(value));
    }

    <T> Future<Optional<T>> submit(Value<T> value) {
        return null;
    }
}

class FutureWrapper 
{
    static <T> Future<T> wrap(final Future<? extends T> future)
    {
        return new Future<T>()
        {
            @Override
            public boolean cancel(boolean mayInterruptIfRunning)
            {
                return future.cancel(mayInterruptIfRunning);
            }

            @Override
            public boolean isCancelled()
            {
                return future.isCancelled();
            }

            @Override
            public boolean isDone()
            {
                return future.isDone();
            }

            @Override
            public T get() throws InterruptedException, ExecutionException
            {
                return future.get();
            }

            @Override
            public T get(long timeout, TimeUnit unit)
                throws InterruptedException, ExecutionException,
                TimeoutException
            {
                return future.get();
            }
        };
    }

}
Community
  • 1
  • 1
Marco13
  • 53,703
  • 9
  • 80
  • 159
1

As far as I know there is no way of telling the compiler that your code is actually correct. You can try replacing the ? with Object:

Value<Object> value = null;
Future<Optional<Object>> future = submit(value);
mvieghofer
  • 2,846
  • 4
  • 22
  • 51
  • unfortunately `Value> value` is passed as a parameter to me and I can't change it's signature – Nutel Jul 24 '14 at 15:01
  • You could cast is to `Value`. The risk of a ClassCastExcpetion is pretty low, I think, because not matter what the actual generic is it is always some derivation of `Object`. – mvieghofer Jul 24 '14 at 15:08
  • @mvieghofer You can but you don't have to. Casting `Foo>` to `Foo` is an almost sure sign of a design fault. – biziclop Jul 24 '14 at 15:10
  • @biziclop I agree with you, but I also think that passing `Value>` to any method (as it seems to be the case here) is also bad design. The best way would be to get rid of the `Value>` parameter. – mvieghofer Jul 24 '14 at 15:13
  • @mvieghofer So how about [this](http://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#reverse(java.util.List))? Passing an unbounded wildcard parameter is often a sign of bad design but it has its legitimate uses. – biziclop Jul 24 '14 at 15:16
  • @biziclop yeah, that's true. There obviously are legitimate use cases. – mvieghofer Jul 24 '14 at 20:07
0

I don't see where the problem is really.

Future<? extends Optional<?>> future = submit(value);
Optional<?> f = future.get();

Compiles and runs correctly.

The answer you linked to explains it quite clearly:

Foo<Bar> is a Foo<?>

But

Foo<Bar<X>> isn't a Foo<Bar<?>>, it's a Foo<? extends Bar<?>>

biziclop
  • 48,926
  • 12
  • 77
  • 104
  • The problem is that Optional is actually Optional> and I was hoping there is a way to tell the compiler to not in the method signature or method call so the signature of the `future` can stay Optional> – Nutel Jul 24 '14 at 15:12
  • This is the way to tell it. The `List` example shows you why. – biziclop Jul 24 '14 at 15:12
  • why does the snippet with `E` works then? In this case it seems like ? is not captured – Nutel Jul 24 '14 at 15:17
  • @user2961393 Because `E` will have to be bound to a specific class, which will have the same value in the entire expression. Whereas `?` literally means anything can go in there. I still don't see why you'd want to do an unsafe cast just to avoid the correct notation. – biziclop Jul 24 '14 at 15:22
  • your example just changes the signature of future so it matches Future> the ? is still captured, there should be a cleaner solution that does not require to "loose" the future's type, the code Future> future = submit(value); should be still correct from the type system perspective – Nutel Jul 24 '14 at 15:23
  • So for example `List – biziclop Jul 24 '14 at 15:26
  • @user2961393 No, it shouldn't. Because when you pass `Value>` in, what you say is this: **I don't know what parameter Value has and I don't care**. So you can't say afterwards that you want the result to have the same type as the input had because by using `?` you declared that you don't care. – biziclop Jul 24 '14 at 15:28
0

You can change your method to use a wildcard operator as a parameter, since you are not specifying any type on T. Seems to me, that it wouldn't change much.

Future<Optional<?>> submit(Value<?> value) {
    //...
}     
mvieghofer
  • 2,846
  • 4
  • 22
  • 51
squallsv
  • 482
  • 2
  • 11
  • Of course it would change much since in the version with `?` the type of the input parameter does not have to match the return value. So you can pass `Value` to the method but return `Future>` and that's probably not what the method should do. – mvieghofer Jul 24 '14 at 15:11
  • the submit method should be typed meaning that the return type and parameter type should match – Nutel Jul 24 '14 at 15:14
  • Yes, i know that, but he's not doing that on his example, meaning that he does not care about the specific type of the return. That's why i wrote that it wouldn't change much in **this** case. – squallsv Jul 24 '14 at 17:58
  • If you say you need to match the parameters, then why you didn't pass `value` with a specific parameter, instead of a wildcard operator? – squallsv Jul 24 '14 at 17:59