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