13

I am trying to undertand how captured conversion works for wildcard types. There is a section in JLS explaining that:

Let G name a generic type declaration (§8.1.2, §9.1.2) with n type parameters A1,...,An with corresponding bounds U1,...,Un.

There exists a capture conversion from a parameterized type G<T1,...,Tn> (§4.5) to a parameterized type G<S1,...,Sn>, where, for 1 ≤ i ≤ n :

  • If Ti is a wildcard type argument (§4.5.1) of the form ?, then Si is a fresh type variable whose upper bound is Ui[A1:=S1,...,An:=Sn] and whose lower bound is the null type (§4.1).

  • If Ti is a wildcard type argument of the form ? extends Bi, then Si is a fresh type variable whose upper bound is glb(Bi, Ui[A1:=S1,...,An:=Sn]) and whose lower bound is the null type.

    glb(V1,...,Vm) is defined as V1 & ... & Vm.

    It is a compile-time error if, for any two classes (not interfaces) Vi and Vj, Vi is not a subclass of Vj or vice versa.

  • If Ti is a wildcard type argument of the form ? super Bi, then Si is a fresh type variable whose upper bound is Ui[A1:=S1,...,An:=Sn] and whose lower bound is Bi.

  • Otherwise, Si = Ti.

The thing that is not clear to me is Ui[A1:=S1,...,An:=Sn]. What does it mean? I could not find a definition for that searching through the JLS.

Turing85
  • 18,217
  • 7
  • 33
  • 58
  • possible duplicate of [What is a capture conversion in Java and can anyone give me examples?](http://stackoverflow.com/questions/4431702/what-is-a-capture-conversion-in-java-and-can-anyone-give-me-examples) – Raman Shrivastava Jul 03 '15 at 13:13
  • 2
    @RamanShrivastava Unfortunately, it's not. I asked about the specific part of the definition. –  Jul 03 '15 at 13:14
  • If you add the extra context at the start *Let G name a generic type declaration (§8.1.2, §9.1.2) with n type parameters A1,...,An with corresponding bounds **U1,...,Un**.* it becomes a little clearer what the **Ui** refers to. – OldCurmudgeon Jul 03 '15 at 13:19
  • @OldCurmudgeon - maybe add to that with "... along with [JLS § 1.3](http://docs.oracle.com/javase/specs/jls/se8/html/jls-1.html#jls-1.3) and a bit of grokking it becomes a little clearer what the `Ui` refers to"! – Andy Brown Jul 03 '15 at 15:22
  • Although there was given a good explanation behind the notation, I believe it is still not quite clear why we need one. My understanding is that the bound is the function of type arguments. For example, in the declaration `public class Test {}`, the bound of S (`U_1`) is `Number` but once replaced by type arguments, e.g. `Test t` the `U_1` becomes `Integer` since we can't substitute the first parameter by `Number` anymore because `S` depends on the bound of `T`. Hence, we have to look at `U_1 [A1:=S1,...,An:=Sn]` and not just simply `U_1` – Turkhan Badalov Apr 22 '23 at 09:12

2 Answers2

5

First: define substitution.

[A1:=S1,...,An:=Sn] is a substitution in JLS notation (§1.3), defined as:

The notation [F1:=T1,...,Fn:=Tn] denotes substitution of Fi by Ti for 1 ≤ i ≤ n.

Statement: [A1:=S1,...,An:=Sn] is the substitution of the type parameter (of G) Ai by the type variable Si for 1 ≤ i ≤ n. (also see footnote †)

Next: consider why we might need substitution in the first case. From §5.1.10 (highlighting added to drive home the next point):

Let G name a generic type declaration ... with n type parameters A1,...,An with corresponding bounds U1,...,Un.

That is:

  • the bounds U1,...,Un correspond specifically to the type parameters A1,...,An.
  • the unstated corollary: the bounds U1,...,Un do not correspond to the type variables S1,...,Sn.

Putting it together: I'm now stating the obvious as I'm sure you are ahead of me, but ...

Regarding the rule for "Ti is a wildcard type argument ... of the form ?")

Si is a fresh type variable whose upper bound is Ui [A1:=S1,...,An:=Sn]

  • Si is a fresh type variable
  • whose upper bound is Ui
  • where the (this is the implied bit)
  • type parameters A1,...,An that U1,...,Un correspond specifically to
  • have been substituted by the type variables S1,...,Sn
  • making U1,...,Un correspond to the type variables S1,...,Sn

TL;DR

i.e. It just means that the original upper bound Ui is also the upper bound for Si

Footnotes

† It is helpful to recall from the JLS that type variables and type parameters are not the same thing (hence we can start to see why we need the substitution):

A type variable is an unqualified identifier used as a type in class, interface, method, and constructor bodies.

A type variable is introduced by the declaration of a type parameter of a generic class, interface, method, or constructor.

Laird Nelson
  • 15,321
  • 19
  • 73
  • 127
Andy Brown
  • 18,961
  • 3
  • 52
  • 62
  • BTW, couldn't you add the example of a variable that's not a fresh-type variable? –  Jul 04 '15 at 04:19
  • Sorry @DmitryBundin, I don't understand what you mean. The section you refer to only talks about a "fresh type variable Si"? – Andy Brown Jul 04 '15 at 12:56
  • I meant if the restriction that Si is a __fresh__ type variable is important. I don't understand why they metntioned about that. –  Jul 04 '15 at 14:14
  • @DmitryBundin They just mean `Si` isn't reused from elsewhere, it's a whole new type variable declared for the capture. That's why two captures that should seemingly be the same are not - they have different captured type variables. – Andy Brown Jul 04 '15 at 14:16
  • @AndyBrown - my thoughts on ["type parameter vs type variable"](https://groups.google.com/forum/#!topic/java-lang-fans/5w9No6yGcRc) – ZhongYu Jul 05 '15 at 18:39
1

It means "substitution" of type variables with actual types. For example

List<T>[T:=String]    =>    List<String>

Enum<E extends Enum<E>>
    A1=E
    U1=Enum<E>

Enum<?> capture convertion to  Enum<S1>
    U1[A1:=S1]   =>   Enum<S1>
    S1's upper bound is Enum<S1>

The syntax is likely borrowed from lambda calculus

ZhongYu
  • 19,446
  • 5
  • 33
  • 61