I understand the <? extends T> in Java is crudely equivalent to the existential qualifier (∃) but is <? super T> related to the universal qualifier (∀)?
Feel free to correct me if I'm wrong about ∃.
It's early and I'm confused, so may well be talking nonsense. I could buy that both are existential, as direction need not negate the logic for a "for some" relationship..?
Partially prompted by the fact that List[_] in Scala is described as existential and that's roughly the same as List<?> in Java.
Wildcard types (both ? extends T and ? super T) form a subset of existential types. Both of these you can read like "there exists some type which (extends|is supertype of) T". The key idea is that you don't know exact type.
Universal types are just type parameters. For example, here:
class List<T> { ... }
T is arbitrary, like it has an implicit universal qualifier.
Its not really related to predicate logic, its related to the type hierachy. I can understand why you might read out loud <? extends T> as "For all T's" but its extended to "For all objects that have a super class of T" rather than "For all T in X" as in predicate logic.
Similarly <? super X> should be read as "For objects that are of a type that is a super class on X"
The main difference between <? super T> and <? extends T> is that the first declaration says that some type is an ancestor of T and the second says that some type is a subclass of T. I don't see any correlation with existential qualifier or universal qualifier here. As someone noticed in the comments, the more likely similarity (if you really must have one) is type floor and ceiling. Nevertheless, it's really an abstract analogy.
Related
Suppose I have this (contrived) situation:
public final Comparable<? super Number> frob() {
return x -> 0; // whatever
}
final Comparable<? super Integer> c = frob();
The JLS defines assignability of reference types in terms of supertypes and subtypes only. Fine.
One of the direct supertypes of a parameterized type is an otherwise equivalent parameterized type with an appropriate containing type (a wildcard expression) in one of its type argument slots. A parameterized type with the same raw type and owner type and that containing type argument (among its others) is thus a direct supertype of the original parameterized type. (So by these rules Comparable<?> is a direct supertype of Comparable<Whatever>, as is Comparable<? extends Whatever>, and Comparable<? super Whatever>, and plenty of others that section 4.5.1 lays out.)
The implication of all this is, loosely speaking, if you have a "receiver" reference a bearing type A in your left hand, and a "payload" reference b bearing type B in your right hand, then b is assignable to a if and only if A is a supertype (not just direct) of B. So presumably what the compiler does is calculate B's supertypes, and then see if the resulting collection of types contains A.
I must be wrong in this presumption, though, because analyzing the supertypes of Comparable<? super Number> by itself following these rules will seemingly never yield Comparable<? super Integer>. (That is, looking at just the type arguments, if you "start from" Number and "go up" its supertype hierarchy to calculate its containing types, you'll never "reach" Integer, because as we all know Integer is a subtype of Number, not a supertype of it.)
So in my example above, what rules in the JLS permit Comparable<? super Integer> to be derived as a direct supertype of Comparable<? super Number>? Is it to be found in the section on type inference, even though to my eye there's no inference going on here (i.e. no diamond operator, no var, etc.)?
To make it clear: my problem is not with the assignment, which I know in practice is of course just fine (if the example method above returns a new Comparable<Object> anonymous class, for example, that would work). It's with my understanding of how the JLS allows this.
I was reading about reasons why kotlin does not have wildcards (https://kotlinlang.org/docs/reference/generics.html). It all came to the declaration-site variance. We have <in T> and <out T> constructions which should replace wildcards. I think I understood how <out T> works but I have troubles with <in T>. So in java we could write something like this:
public List<? extends Number> list1;
public List<? super String> list2;
First case after initialization becomes read only list (though not perfectly immutable cause we could clear it) which could be read if we treat every element as Number.
Second case is write only (though we could read it if we treat every element as Object). We could write there String and it subclasses.
In Kotlin I was able to recreate list1 example using <out T> like this:
class Service {
val container = Container(mutableListOf("1", "2", "3"))
}
class Container<T>(var list1: MutableList<out T>)
Finally I tried something similar with <in T> thinking that I could recreate list2 example, but I failed:
Can someone explain to me how to achieve my list2 example in Kotlin? How should I use <in T> construction in proper way?
Kotlin List<E> is not equivalent to Java List<E>. The Java list has the mutating functions, while the Kotlin list is read-only. It's Kotlin MutableList<E> that is equivalent to the Java list.
Next, take a look at the List<E> declaration: its type parameter is covariant (out E), and the declaration-site variance cannot be overridden by use-site variance, that's why you cannot have a List<in T>.
Moreover, the declaration-site variance out E means that E never appears in an in-position (there's no function parameter of type E and no mutable property of type E), and indeed, since List<E> is read-only, it doesn't take E into any of its functions (*).
You can convert your example to use MutableList<E> instead:
class Container2<T>(var list2: MutableList<in T>)
The MutableList<E> interface has its E invariant, and the in-projection at use-site does not conflict with declaration-site variance.
(*) Actually, it does, but only using the parameters that are marked with the #UnsafeVariance annotation, which simply suppresses the variance conflict, more about it can be found here.
Also, a small remark:
It all came to the declaration-site variance. We have <in T> and <out T> constructions which should replace wildcards.
It's actually use-site variance that replaces Java wildcards. Declaration-site variance is only applied at the type parameter declaration (where the type is defined), and when it is, all the usages of the type will have that variance (e.g. when you use List<CharSequence>, it's actually a List<out CharSequence> because of the declaration-site variance of List<out E>). And use-site variance is, accordingly, for particular usages of a generic type.
I have read in generics that "? extends Object" and "?" are synonymous then why this occurs.
List list=new ArrayList();
List<? extends Object> list2=list; //1
List<?> list3=list; //2
For 1 unchecked conversion warning is thrown but not for 2. So the compiler somewhere is definitely differentiating between the two.
Plz explain the difference between the two with respect to the above code
I have read in generics that "? extends Object" and "?" are synonymous
Not quite. The first wildcard has a lower bound, the second does not. For your two examples it should not make a difference (well, except that you can only add null to list2 and list3!).
This lower bound can make a difference: "erasure signature" (I don't know the exact term).
The best example for this is Collections.max(); you will notice that the parameter type is defined as T extends Object & Comparable<? super T>.
This is because prior to Java 5 this method existed and was defined as:
static Object max(Collection coll)
If the type parameter were defined as T extends Comparable<? super T>, this would have meant that the method in 1.4 would have had to return a Comparable!
Because some type information is erased during compilation, not all types are available at run time. Types that are completely available at run time are known as reifiable types(see http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.7).
So according to JLS List<?> is a reifiable type, but List<? extends Object> is not, which means they are not the same from compiler point of view.
Class<? super T> getSuperclass()
The getSuperclass() in Class class return a Class whose type is<? super T>, which mean that the type parameter of Class of the Super could be T or any of its Superclasses, now how come a SuperClass's Class type parameter be the same type as the subclass?
for example
Class<Manage>.class.getSuperclass()
doesn't return
Class<Manager>
at all ..like never
Does this make sense? or i am missing something here?
The bound is just a overly-broad because it's as close as you can express using Java's generics.
What you really want is <the immediate superclass of T>; but there's no way to write that in Java's generics. There's also no way to write <? super T excluding T>. <? super T> is pretty much as specific as you can get given the way Java's generics work.
For what it's worth you can guarantee that the class you get back will be the superclass in question -- no matter what its type bound is.
There's no way with Java generics to specify "some superclass but not the class itself." So the provided bound is the best one you can possibly specify.
Think i ask this question before but still don't understand to a certain degree.
From raw to <?> - no unchecked conversion warning. Understood since both are reifiable type.
From raw to <? extends Object> - unchecked conversion warning. Understood since <? extends Object> is a non reifiable type.
From <?> to <? extends Object> - no unchecked conversion warning. Why? Since the former is a reifiable type and the latter is not. I see this as similiar to clause 2.
<?> and <? extends Object> are actually the same thing, and should be interchangeable.
Actually, since List<? extends Object> is a super type of List<?> (vice versa), if it's safe to convert List to List<?>, it should also be safe to convert List to List<? extends Object>.
The spec requires unbounded wildcard <?> in some places, while the twin brother <? extends Object> is not mentioned (therefore forbidden). There's no theoretical reason for that; the language designers probably reasoned that <?> is enough for practical use cases.
For example, in 5.1.9 Unchecked Conversion, converting raw G to G<T1..Tn> generates a mandatory compile-time warning unless all Ti=?. This is a little too harsh; a counter example:
class G<N extends Number>{}
G x = ...;
G<? extends Number> y = x; //warning, tho absolutely safe
the conversion from x to y is safe, and the warning is really unnecessary.
It is possible to relax the rule to exempt all safe conversions.
We know it is safe to convert raw G to G<?..?>; furthermore, if G<T1..Tn> is a super type of G<?..?>, converting G to G<T1..Tn> is also safe, and should be allowed without warning. This certainly makes sense.
However, checking that G<?..?> is a subtype of G<T1..Tn> is not a trivial task; the language designer probably said, to hell with it, it's not worth the trouble to do this for unchecked conversion, which is not an important part of the type system anyway.
<?> means it can be any subtype.
Every subtype of that will always extend Object.
I believe you wouldn't have a problem if you went from <? extends Number> to <? extends Object> either.