14

Let's say I need a class that is bounded to a generic Comparable type:

class A<T extends Comparable<T>> {

    // this is just an example of usage of T type
    List<T> comparables;

    int compareSomething(T smth) {
        return comparables.get(0).compareTo(smth);
    }
}

The class has a method with own generics in signature:

<V> Future<V> submit(Callable<V> task) {
    return someExecutorService.submit(task);
}

Now, is there a possibility to restrict the input of the submit method to accept only Callables that also implement T? I first tried this:

<V, W extends T & Callable<V>> Future<V> submit(W task) {
    if(compareSomething(task) != 0)
        throw new RuntimeException("");
    return someExecutorService.submit(task);
}

but found out it's not possible (for reasons described here). Is there any elegant possibility to bypass it?


EDIT: The one ugly possibility I can think about is to split the encapsulation in two different types and pass an object pair in submit:

class A<T extends Comparable<T>> {

    // this is just an example of usage of T type
    List<T> comparables;

    int compareSomething(T smth) {
        return comparables.get(0).compareTo(smth);
    }
    <V> Future<V> submit(Callable<V> task, T comparable) {
        if(compareSomething(comparable) != 0)
            throw new RuntimeException("");
        return someExecutorService.submit(task);
    }
}

The main disadvantage is that the method signature becomes more complicated, also I will need some one-to-one mapping of Ts to Callables for some latter code. Maybe one can suggest a pattern that solves it in an appropriate way?..


EDIT, take two: Let me explain briefly what I'm trying to achieve. I'm working on a custom thread pool implementation that is able to perform some kind of special task scheduling. To do so, this service accepts only one special sort of Callable tasks. Those Callables have to implement a custom interface that is similar to the Comparable one. By comparing pairs of tasks using methods in this interface, the service will:

  1. Block the incoming task if it is blocked by any running task.
  2. Invoke pending tasks on completion of a done task's Future.
  3. Determine the execution order of pending tasks by comparing them.

The blocking/comparison logic should be provided by the tasks themselves. This way the thread pool class should only define what special kind of Comparables the pool object is accepting, and it doesn't care at all what kind of Callables they really are and what is their return type.


EDIT, take three: Based on Erick Robertson's answer, it's now possible to prevent submitting of smelly tasks:

public static void test(String[] args) {
    A<Valid> scheduler = new A<>();
    scheduler.betterSubmit(new Valid()); // applies to method signature
    scheduler.betterSubmit(new Forbidden()); // rejected on compile time
    scheduler.betterSubmit(new ConformWithValid()); // still appliable because all required interfaces implementations recognised
}

// just a bunch of test classes

private static class Valid implements Comparable<Valid>, Callable<Void> {

    @Override
    public int compareTo(Valid o) {
        return 0;
    }

    @Override
    public Void call() throws Exception {
        return null;
    }
}

private static class Forbidden implements Comparable<Forbidden>, Callable<Void> {

    @Override
    public int compareTo(Forbidden o) {
        return -1;
    }

    @Override
    public Void call() throws Exception {
        return null;
    }
}

private static class ConformWithValid implements Comparable<Valid>, Callable<Boolean> {

    @Override
    public int compareTo(Valid o) {
        return 1;
    }

    @Override
    public Boolean call() throws Exception {
        return Boolean.FALSE;
    }
}

Nice and easy! Hope some day this will help someone in the same situation as mine. :-)

Community
  • 1
  • 1
hoefling
  • 59,418
  • 12
  • 147
  • 194
  • 4
    Closely related: [Why can't I use a type argument in a type parameter with multiple bounds?](http://stackoverflow.com/q/197190) – Duncan Jones Sep 29 '14 at 09:44

7 Answers7

3

Use Comparable<T> to constrain the parameter instead of just T.

If the only criteria is that the object is Callable and Comparable, then you can just put those two interfaces on the argument. That even reserves the option of adding a named class to the parameter if this is required to fill another requirement. You'll need to suppress one warning, but it's a safe suppression because you know that T extends Comparable<T>.

public class A<T extends Comparable<T>> {

    // this is just an example of usage of T type
    List<T> comparables;

    ExecutorService someExecutorService = null;

    int compareSomething(T smth) {
        return this.comparables.get(0).compareTo(smth);
    }

    <V> Future<V> submit(Callable<V> task) {
        return this.someExecutorService.submit(task);
    }

    @SuppressWarnings("unchecked")
    <V, W extends Callable<V> & Comparable<T>> Future<V> betterSubmit(W task) {
        if(this.compareSomething((T) task) != 0)
            throw new RuntimeException("");
        return this.someExecutorService.submit(task);
    }
}

I've run into this same problem with another class that I have which references itself as its own generic parameter like this. I don't think it's a clean implementation yet, but I like your example. It provides a nice neat use case which I might be able to pattern some new code after. I generally don't like suppressing warnings, but I don't really mind it since it's only this method which is affected. I hope this will help!

Erick Robertson
  • 32,125
  • 13
  • 69
  • 98
2

I think Erick Robertson's answer comes closest to a direct solution. I'd like to propose a less direct one (which avoids any unchecked casts). You wrote:

this service accepts only one special sort of Callable tasks. Those Callables have to implement a custom interface that is similar to the Comparable one.

If we actually declare what you described as a type, we come up with this intersection interface:

interface CustomCallable<V> extends Callable<V>, Comparable<CustomCallable<?>> { }

Notice how it implements Comparable<CustomCallable<?>>, not Comparable<CustomCallable<V>>. This is because I'm assuming CustomCallables of different output types should still be comparable to each other by the pool. Otherwise there'd be no point to having V as a method type parameter.

Assuming your pool can accept any type of that intersection interface, we can just remove T entirely and the language limitation is moot:

class A {

    List<CustomCallable<?>> customCallables;

    int compareSomething(CustomCallable<?> smth) {
        return customCallables.get(0).compareTo(smth);
    }

    <V> Future<V> submit(CustomCallable<V> task) {
        if (compareSomething(task) != 0) {
            throw new RuntimeException("");
        }
        return someExecutorService.submit(task);
    }
}

If you insist on parameterizing A on a specific type of custom callable, it gets more complicated. The only way to make it work is to add a "self type" parameter to the intersection interface:

interface CustomCallable<V, SELF> extends Callable<V>, Comparable<CustomCallable<?, ?>> { }

Here, SELF is intended to represent the type of the implementor itself. Note that there's no way for that to be enforced however. More info about self types and their caveats on my answer here: Is there a way to refer to the current type with a type variable?

With the added self type, it's now possible for A to declare a T that submit then insists be used for the self type of the custom callables it's provided:

class A<T extends CustomCallable<?, ?>> {

    List<CustomCallable<?, T>> customCallables;

    int compareSomething(CustomCallable<?, T> smth) {
        return customCallables.get(0).compareTo(smth);
    }

    <V> Future<V> submit(CustomCallable<V, T> task) {
        if (compareSomething(task) != 0) {
            throw new RuntimeException("");
        }
        return someExecutorService.submit(task);
    }
}

Here's an example of a CustomCallable implementation, which resolves the self type:

class MyCustomCallable<V> implements CustomCallable<V, MyCustomCallable<?>> {
    ...
}

Similarly to before, notice how the self type is "relaxed" to MyCustomCallable<?> rather than MyCustomCallable<V> since different output types are interchangeable by design.

And here's a usage example:

A<MyCustomCallable<?>> pool = new A<>();

MyCustomCallable<String> strCallable = ...;
MyCustomCallable<Integer> intCallable = ...;

Future<String> strFuture = pool.submit(strCallable);
Future<Integer> intFuture = pool.submit(intCallable);
Community
  • 1
  • 1
Paul Bellora
  • 54,340
  • 18
  • 130
  • 181
  • This is also a very good answer and I like your idea along with the clean explanations. Unfortunately, I have to bound the scheduler class to a specific task type. Nevertheless, you just gave me an answer for another problem I'm currently stuck with, so it's a shame I cannot award a bounty for you either... – hoefling Oct 07 '14 at 12:18
1

I don't see how you can combine both your generic class parameter T and the V in the Callable<V> method argument, for the reasons listed in the answers to the linked post. However, maybe it would be an option - I cannot estimate how counterintuitive that would be, though -- to change the act of submitting a task to a method being invoked on the task itself? Something along the lines of...

class A<T extends Comparable<T> & Callable<?>> {

    public static abstract class Submittable<T extends Submittable<T,V>,V>
      implements Comparable<T>, Callable<V> {
        // ugly, but unavoidable
        @SuppressWarnings("unchecked")
        public Future<V> submitTo(A<? super T> scheduler) {
          return (Future<V>) scheduler.submit((T) this);
        }
    }

    // this is just an example of usage of T type
    List<T> comparables;

    int compareSomething(T smth) {
        return comparables.get(0).compareTo(smth);
    }

    // *can* be left public, but that way you enforce a single way
    // of submitting tasks, namely via submitTo
    private Future<?> submit(T task) {
        if(compareSomething(task) != 0)
            throw new RuntimeException("");
        // the following cast is a save conversion - you could also write it cast-free
        // as Callable<?> callable = task; ...submit(callable);
        return someExecutorService.submit((Callable<?>) task);
    }
}

Now, your tasks all have to inherit A.Submittable, and then can be submitted to a scheduler instance via submitTo, returning a Future<V> for the correct type V.

Of course, this crucially relies on T in fact being a selftype of the subclasses of Submittable. And what's going on in submitTo is - well, ugly. But it does provide you with the convenience of returning a Future<V> of the correct type.

misberner
  • 3,488
  • 20
  • 17
  • Thanks, this could be also an option, although the answer I accepted offers less explicit casting throughout the class. – hoefling Oct 07 '14 at 12:11
0

Does this solve the problem?

class A<V, T extends MyT<T, V>> {

    // this is just an example of usage of T type
    List<T> comparables;

    int compareSomething(T smth) {
        return comparables.get(0).compareTo(smth);
    }

    public <V> Future<V> submit(MyT<T, V> task) {
        return ...;
    }
}

class MyT<T, V> implements Comparable<T>, Callable<V> {

    @Override
    public int compareTo(T o) {
        return 0;
    }

    @Override
    public V call()
        throws Exception {

        return ...;
    }
}
TedTrippin
  • 3,525
  • 5
  • 28
  • 46
  • Unfortunately not, because `MyT` is not conform to `T` and `compareSomething` won't be appliable to `MyT`. (You can also imagine adding the submitted task to `comparables` list or anything similar instead of calling `compareSomething`, the exact functionality doesn't matter at that point.) Also - although this does not affect the actual problem - I don't want to bound the whole class to a specific return type of `Callable`s, so I cannot allow `V` in class signature. – hoefling Sep 30 '14 at 15:57
0

Something like this could work:

class A<T extends Comparable<T>> {
    List<T> comparables;

    int compareSomething(T smth) {
        return comparables.get(0).compareTo(smth);
    }

    public Future<T> submit(B<T> task) {
        return someExecutorService.submit(task);
    }

    public class B<T> implements Callable<T> {
        ...
    }  
}
0

OK, really last try. Can you change your generics function to a generics nested or inner class ? Like this:

class A<T extends Comparable<T> >  {


    // this is just an example of usage of T type
    List<T> comparables;

    int compareSomething(T smth) {
        return comparables.get(0).compareTo(smth);
    }

    class B<V> 
     {
      T t;
      T getT() { return t; }
      Callable <V> v;
      Callable <V> getV() { return v; }
      public Future<V> submit(B<V> task) {
           if(compareSomething(task.getT()) != 0)
            throw new RuntimeException("");
        return SomeExecutorService.submit(task.getV());
    }
}
Gonen I
  • 5,576
  • 1
  • 29
  • 60
  • Same problem here - defining `V` as `Callable`s result type would bound the whole class to one specific type of `Callable`s. Also, the definition `V extends Callable` doesn't make sense at all - the class would then be able to proceed only `Callable`s that return another `Callable`s. I will enhance the question with more details to clear some fog there. – hoefling Oct 02 '14 at 21:52
  • OK, gotcha. Then how about combining the methods like this? I guess not - V is still not free to vary within a single T. – Gonen I Oct 02 '14 at 22:10
  • Still having the problem that the class is bounded to `V`. Please read the second edit I made to the question with the explanations; hope it makes the whole thing easier to understand. Nevertheless, I'm starting to think that there's no way to solve the actual problem by shuffling the generics usage around the class; what I probably need is a good idea for class design. – hoefling Oct 02 '14 at 22:17
  • T should no longer be bounded to V, but I'm having a hard time visualizing your thread pool implementation, so don't know if it's appropriate. – Gonen I Oct 02 '14 at 22:33
0

Why won't something simple like this work?

public class CustomThreadPool {
    public <CallableReturn> Future<CallableReturn> submit(SelfSchedulingCallable<CallableReturn> task) {
        // Use comparePriority or any other interface methods needed to determine scheduling
    }
}

public interface SelfSchedulingCallable<V> extends Callable<V> {
    public boolean isBlockedBy(SelfSchedulingCallable<?> otherTask); // Doesn't care about the return type of otherTask
    public boolean invokeAfter(SelfSchedulingCallable<?> otherTask);
    public int comparePriority(SelfSchedulingCallable<?> otherTask);
}
Floegipoky
  • 3,087
  • 1
  • 31
  • 47