Compatibility goals

Brian Goetz brian.goetz at
Wed Jun 1 21:44:57 UTC 2016

> /> Alpha-renaming a type variable (to a non-shadowed name) should be 
> binary and source compatible./
> The name is only used internally in the generic class in the 
> GenericClass attribute, and recompiling with different names will 
> therefore not affect users of the generic class.

Right.  (Like method parameter names, the name is not part of the API, 
and exist only to improve the readability of the implementation code.)

> /> Reordering or removing type variables is not compatible. (These 
> first two together match the story for method argument lists; you can 
> rename method arguments, but not reorder or remove them.)/
> Other classes will refer to the generic class using ParamTypes in 
> their CPs. ParamType provides the type parameters in the order that 
> the generic type specified at compilation time. Reordering and 
> recompiling will therefore invalidate all ParamTypes referring to the 
> modified generic type.

Right.  Once you've published Foo<any X, any Y>, clients or subclasses 
may have Foo<A,B> in their source files and ParamType[Foo, A, B] in 
their binaries, which they expect to retain their meaning.  Dropping or 
reordering parameters would render these client / subclasses broken.

> /> Anyfying an existing erased type variable should be binary and 
> source compatible./
> All ParamTypes referring to a ref-generic type variable will be 
> providing a reference type (erased) as the type parameter (or no 
> parameters?). As references are a subset of any, anyfying the type 
> variable does not invalidate existing ParamTypes.
> I have one question here: What happens if I refer to Foo<T> (not any 
> T) using ParamType[Foo, String]? Is it valid because String is a 
> reference type, or invalid because Foo is not specializable?
There are two migration situations here:
  - Migrating a totally erased generic class to any-generic (Foo<T> to 
Foo<any T>)
  - Migrating a partially anyfied class (Foo<any T, U> to Foo<any T, any U>)

For the former, there will be no ParamType entries, all references to 
Foo<T> will be LFoo; / Constant_Class[Foo].  For the latter, there will 
be ParamType entries that specify 'erased' in the appropriate position.  
In either case, these remain valid parameterizations after the migration.

To your question: I would say this is invalid, because Foo is not 
specializable / lacks a GenericClass attribute.

> /> Adding a new type variableat the endof the argument list should be 
> binary compatible (though not source compatible.) Adding a new type 
> variable other than at the end is not compatible./
> The last point already said that we have to support missing type 
> parameters, and this point is really just and extension of that. If a 
> type parameter is not provided, the type variable is assumed to be erased.


Also, this one interacts with the story for inner classes, and 
influences the decision about how to represent enclosing class type 
parameters in ParamType (do we have a chain of ParamType, as proposed by 
the M3 doc, or do we lift all type parameters to the innermost class?)  
The chain approach seems to reduce the impact of generifying an 
enclosing class (as per the next item.)

> /> Generifying an enclosing scope (evolving|Outer.Inner<U>|to 
> |Outer<T>.Inner<U>|) should be binary compatible./
> At first glance, this might look like anyfying an existing erased type 
> or generifying a non-generic class. However, the complicating factor 
> is that the added type variable will also be added to the scope of the 
> enclosed class, and the question becomes whether we can handle this. 
> An enclosed class must be compiled with its enclosing class, so the 
> GenericClass attribute will be updated correctly. The type parameters 
> to Inner and Outer are provided separately, and any missing type 
> parameter will still be treated as erased.

Right.  Also, with the chain-of-enclosing-descriptors approach, it is 
fairly easy for a ParamType[parent=Outer<T>, Inner, U] to recover from 
new parameters being added to Outer, whereas if we simply lifted the 
Outer parameters onto Inner, now we'd have a difficult time to 
reconstruct the actual parameterization.

> /> Changing type variable bounds is not binary compatible./
> Type variables are erased to their bound, i.e. not necessarily 
> j.l.Object. Any descriptor that contained a type variable will 
> therefore contain the bound after compilation. Changing the bound 
> invalidates the descriptors in existing method refs, and is therefore 
> binary incompatible. Also, this is not a new constraint, as it already 
> applies to erased generics.


More information about the valhalla-spec-observers mailing list