Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delay binding of second-level type parameter

This is a bit of a contrived reproducing case, but bear with me.

Suppose you want to create an adder interface for classes capable of adding items to different types of lists with the following behavior:

// Can add items to any type of array list.
Adder<ArrayList> arrayListAdder = ...;
// Ok. Right list type and item types match.
arrayListAdder.add(new ArrayList<String>(), "test");
// Ok. Right list type and item types match.
arrayListAdder.add(new ArrayList<Integer>(), 3);
// Compile error. Item types do not match.
arrayListAdder.add(new ArrayList<Integer>(), "test");
// Compile error. Wrong list type although item types match.
arrayListAdder.add(new LinkedList<String>(), "test");

In other words, I want the interface to say:

An adder for an specific list type has a method 'add'. This method takes two arguments. The first is a list of this specific type with items of type T. The second argument is an item of type T. The method adds the item to the list.

I tried with different solutions along the lines of:

interface Adder<L extends List<?>> {
    <T> void add(L<T> list, T t);
}

But the expression L<T> is illegal in its context. The error message I get is "Type 'L' does not have type parameters".

I cannot find a way of leaving the type parameter of the list open until the definition of the add method. Is there any way of specifying this interface, or does that require higher-order generics or something else which Java doesn't have?

like image 749
Alexander Torstling Avatar asked Sep 05 '26 04:09

Alexander Torstling


2 Answers

Unfortunately, Java Generics do not support the functionality you are looking for. The closest you can get is to require a List in the method, and not use type L. Such as:

interface Adder
{
    <T> void add(List<T> list, T t);
}

This isn't what you are looking for though, so the next closest thing would be to move your List declaration into the method body, however this is also incorrect:

interface Adder
{
    <T, L extends List<T>> void add(List<T> list, T t);
}

The problem is you are attempting to assign a generic type to an arbitrary type (L), while L may not be genericized, despite forcing L extends List<?>. There is no good way to force the check at compile time or at run time of the list type.

like image 73
Eric Siebeneich Avatar answered Sep 07 '26 18:09

Eric Siebeneich


interface Adder<T, L extends List<T>> {
    void add(L list, T t);
}

class ArrayListAdder implements Adder<String, ArrayList<String>> {
    @Override
    public void add(ArrayList<String> list, String t) {
        list.add(t);
    }
}

I don't think binding T is possible at add definition time, since T must be known in order to declare L having a type parameter (it must be given in either bound or unbound form).

I believe you are looking for the equivalent of this C++0x code:

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>

template <template <typename _ElementT, typename _AllocatorT> class CollectionT>
struct Adder {
    template <typename ElementT, typename AllocatorT>
    void add(CollectionT<ElementT,  AllocatorT> &collection, ElementT element);
};

struct VectorAdder : public Adder<std::vector> {
    template <typename ElementT, typename _Alloc>
    void add(std::vector<ElementT,  _Alloc> &vector, ElementT element) {
        vector.push_back(element);
    }
};

int main() {
    std::vector<int> vi;
    vi.push_back(1);

    std::vector<double> vd;
    vd.push_back(1.1);

    VectorAdder va;
    va.add(vi, 2); // instantiates VectorAdder::add<int, ...>
    va.add(vd, 2.2);  // instantiates VectorAdder::add<double, ...>

    for_each(vi.begin(), vi.end(), [](int x) { std::cout << x << ' '; });
    for_each(vd.begin(), vd.end(), [](double x) { std::cout << x << ' '; });
    return 0;
}

And I'm pretty sure that's not possible in Java.

like image 38
Irfy Avatar answered Sep 07 '26 16:09

Irfy



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!