I don't know Scala, but I'd wager a guess based on my understanding of Java's wildcards.
If the type of an expression contains wildcard, java does "wildcard capture" on it
expr: "foo".getClass()
type: Class<? extends String>
after wildcard capture
type: Class<X>, for some X that X<:String
The two types are not exactly the same, the 2nd type is more specific (which is the reason to do wildcard capture in the first place, so that we get more type info on the expression)
"Wildcard capture" is applied extensively, on any expression. Therefore in almost all cases, a type containing a wildcard can be said to be equivalent to the type after capture conversion. For example the type of expression "foo".getClass()
is Class<? extends String>
, but we can equivalently think of its type as Class<X>, for some X that X<:String
But the two types are not always exchangeable. In Java, the 2nd type is not denotable; suppose it is, meaning we can declare a type like that
Class<Y>(for some Y<:String) var = "foo".getClass();
That line should not compile, because the right hand side, after capture conversion, gets a different, unrelated type variable, say X. So the line tries to assign Class<X> to Class<Y>
.
This works
Class<? extends String> var = "foo".getClass();
because Class<X>(where X<:String)
is a subtype of Class<? extends String>
. As a matter of fact,
for any X<:String, Class<X> <: Class<? extends String>
which can be considered the definition of the wildcarded type, which is essentially a union.
o instanceof Class<? extends String>
iff
there exists X<:String and o instanceof Class<X>
(Java type system does not consider the fact that, String
is final so all these types are pretty much the same, since they all contain the same element, String.class)
We can say the two types are equivalent when we talk about expression types; they are not equivalent when we talk about variable types.