Use the subtype of a class in a generic class

I'm trying to use the generic type of a class in another class that uses this one:

Kotlin

class Callback <O> () 

class Controller <E> (callback: E) where E: Callback<O> {
    fun foo1 (a: O) {...}
    fun foo2 (): O {...}
}

Java

class Callback <O> {}

class Controller <E extends Callback<O>> {
    Controller(E callback) {}
    public void foo1(O a) {...}
    public O foo2() {...}
}

An easy solution is to declare both types E and O on the Controller class in this way:

Kotlin

class Controller <E, O> (callback: E) where E: Callback<O> { ... }

Java

class Controller <E extends Callback<O>, O> { ... }

However, I want to avoid to declare both types on the constructor because the information is repeated and it is not so pretty.

Edit

I need the type E on the constructor because I need to define functions such as:

class StringCallback: Callback<String>() { ... }

fun example(callbackParam: Controller<StringCallback>) { ... }

I want the object callbackParam uses my defined StringCallback, not any Callback<String>.

And remember that I also need the O type in theController class to operate with this type. Can I "extract" or "infer" it without declaring it in the generic constructor?

[@LppEdd with your permission I'll use your class :) ]

Any idea?

Thanks in advance!!

Upvotes: 2

Views: 1866

Answers (3)

LppEdd
LppEdd

Reputation: 21104

What you can do is

class Controller<E> {
    private final Callback<E> callback;

    Controller(final Callback<E> callback) {
        this.callback = callback;
    }

    public void foo1(final E a) { callback.set(a); }
    public E foo2() { return callback.get(); }
}

Example:

final Controller<String> stringController = new Controller<>(new Callback<>());

That's because you already know you'll accept a Callback<?>.
There is no need to use E extends Callback. But keep reading

This

Controller(final Callback<? extends E> callback)

means the constructor will accept every type which is a subtype of Callback<E>

class StringCallback extends Callback<String> { ... }
class IntegerCallback extends Callback<Integer> { ... }

final Controller<String> c1 = new Controller<>(new StringCallback());
final Controller<Integer> c2 = new Controller<>(new IntegerCallback());

Upvotes: 2

Lino
Lino

Reputation: 19926

You don't need to know the type of the Callback just that it's generic parameter is E.

So you can declare your class in Kotlin like this:

class Controller<O>(callback: Callback<O>) { ... }

And in java like this:

public class Controller<O> {
    public Controller(Callback<O> callback) { ... }
}

Declaring the type of the Callback to be generic would only make sense if you'd allow the caller of your controller to explicitly interact with the callback. But from your given code you just return or accept values from / to the callback.

Upvotes: 2

Eugene Petrenko
Eugene Petrenko

Reputation: 4982

You may shorten the code:

class Controller<E : Callback<O>, O> (callback: E) { .. }

But it will not let you a chance to get rid of the second generic parameter. You use the O type in the functions of your class.

You may try to say class Controller<E: Callback<*>> or class Controller<E : Callback<Any>> if you do not need the actual O type in the code of the Controller class.

Using the Callback<Any> may require to declare the Callback type parameters with variance. In Kotlin one defines variance at the declaration level. See https://kotlinlang.org/docs/reference/generics.html#declaration-site-variance
for more details.

Upvotes: 1

Related Questions