Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't you have multiple interfaces in a bounded wildcard generic?

I know there's all sorts of counter-intuitive properties of Java's generic types. Here's one in particular that I don't understand, and which I'm hoping someone can explain to me. When specifying a type parameter for a class or interface, you can bound it so that it must implement multiple interfaces with public class Foo<T extends InterfaceA & InterfaceB>. However, if you're instantiating an actual object, this doesn't work anymore. List<? extends InterfaceA> is fine, but List<? extends InterfaceA & InterfaceB> fails to compile. Consider the following complete snippet:

import java.util.List;  public class Test {    static interface A {     public int getSomething();   }    static interface B {     public int getSomethingElse();   }    static class AandB implements A, B {     public int getSomething() { return 1; }     public int getSomethingElse() { return 2; }   }    // Notice the multiple bounds here. This works.   static class AandBList<T extends A & B> {     List<T> list;      public List<T> getList() { return list; }   }    public static void main(String [] args) {     AandBList<AandB> foo = new AandBList<AandB>(); // This works fine!     foo.getList().add(new AandB());     List<? extends A> bar = new LinkedList<AandB>(); // This is fine too     // This last one fails to compile!     List<? extends A & B> foobar = new LinkedList<AandB>();   } } 

It seems the semantics of bar should be well-defined -- I can't think of any loss of type-safety by allowing an intersection of two types rather than just one. I'm sure there's an explanation though. Does anyone know what it is?

like image 544
Adrian Petrescu Avatar asked Jul 10 '11 19:07

Adrian Petrescu


People also ask

What happens when we use a bounded wildcard?

Use an upper-bounded wild card only when values are to be retrieved and processed and the data structure (ArrayList) won't be changed. This means that the corresponding argument of a call on m2 can be an ArrayList whose elements are of any class that is Integer or a superclass of Integer, including Number and Object.

CAN interfaces have generics?

Generic Interfaces in Java are the interfaces that deal with abstract data types. Interface help in the independent manipulation of java collections from representation details. They are used to achieving multiple inheritance in java forming hierarchies. They differ from the java class.

What is upper bounded wildcards in generics?

You can use an upper bounded wildcard to relax the restrictions on a variable. For example, say you want to write a method that works on List<Integer>, List<Double>, and List<Number>; you can achieve this by using an upper bounded wildcard.

What is a generic wildcard?

The question mark (?) is known as the wildcard in generic programming. It represents an unknown type. The wildcard can be used in a variety of situations such as the type of a parameter, field, or local variable; sometimes as a return type.


1 Answers

Interestingly, interface java.lang.reflect.WildcardType looks like it supports both upper bounds and lower bounds for a wildcard arg; and each can contain multiple bounds

Type[] getUpperBounds(); Type[] getLowerBounds(); 

This is way beyond what the language allows. There's a hidden comment in the source code

// one or many? Up to language spec; currently only one, but this API // allows for generalization. 

The author of the interface seems to consider that this is an accidental limitation.

The canned answer to your question is, generics is already too complicated as it is; adding more complexity might prove to be the last straw.

To allow a wildcard to have multiple upper bounds, one has to scan through the spec and make sure the entire system still works.

One trouble I know would be in the type inference. The current inference rules simply can't deal with intersection types. There's no rule to reduce a constraint A&B << C. If we reduced it to

    A<<C    or     A<<B 

any current inference engine has to go through major overhaul to allow such bifurcation. But the real serious problem is, this allows multiple solutions, but there's no justification to prefer one over another.

However, inference is not essential to type safety; we can simply refuse to infer in this case, and ask programmer to explicitly fill in type arguments. Therefore, difficulty in inference is not a strong argument against intercection types.

like image 95
irreputable Avatar answered Sep 17 '22 12:09

irreputable