Questions on Template Classes proposal

Brian Goetz brian.goetz at
Wed Mar 13 18:21:08 UTC 2019

Some quick answers…

> Where in the template class file are holes allowed? "almost anywhere in the constant pool”

The constant pool is divided into “segments”, and the holes are a property of the segment.  In the original doc, the constraint was that the holes were the first N constants in the segment.  An alternate way to do this is how M3 did it, where there was a “table of contents” early in the classfile, which enumerated the segments, and identified the holes that go with each.  

Whether a hole is defined by a constant pool entry or an entry in a segment table is largely a “syntax” choice.  

Since each segment is associated with a number of holes, and classes/members are associated with segments, it stands to reason that we need to type-check the relationship between the number and kinds of holes in a segment, and an attempt to specialize the class or method defined in that segment. If I have a segment with two holes of kind “TYPE”, its probably an error to instantiate it with three type parameters, or parameters that are not of kind TYPE.  (Though there may be some need to support mismatches for reasons of compatible evolution.)  

Where we would previously reference a class (Constant_Class, or LFoo; descriptor), we instead need a way to reference a species.  The M3 document showed one way to do this; a ParamType constant, which captures the template name and the parameters.  Then, a species is allowed basically anywhere a class was previously — in descriptor strings, in Constant_Class, as the operand of a new/checkcast/instanceof, as the owner of a Field or Method ref, etc.  
> What about the user mode assumption that: if Foo extends Bar, Foo<Point> is a subclass of Bar<Point>

This is handled by the translation scheme.  If Foo<T> extends Bar<T>, then the superclass of Foo<T> will be Bar<T>. In M3, we’d write this as ParamType[Bar, TypeVar[0//Object]], which means that when Foo is specialized with a real type T, the super type is Bar<T>, and when Foo is specialized with erased, the suer type is erased Bar.  

> Is it the case that a specialization could always have two segments

As the proposal is written, a specialized class would have at least two segments — the “true constants” segment, and the “specialized class” segment.  The intent, though, is that nested generic members (methods, and maybe even inner classes) would have their own segment too.  And segments inherit holes from their parents.  

Note too that compilers often desugar one member into more than one; if a generic method has a lambda in it, that lambda will get its own method, but it should go into the segment for the generic method, not the class.  Then the right things happen automatically.  

Bringing inner classes into a single template may sound like a radical move, but its a powerful one; inner classes share so much with their enclosing class, that being able to inherit holes and constants from the class would result in lots more sharing.  

> Why extend super-interfaces to Constant_Dynamic? When would the BSM be invoked? Is the intent here to allow superinterfaces with holes - couldn't that be handled via a template type species? 

John is looking ahead here to a feature we would like to have.  Suppose I have an interface like Comparable.  And suppose I want to create a Box<T> type, and I want to lift the comparability of T onto Box<T>.  That is, if T is ordered, then I can derive an order on Box<T> from the order on T.  And I would like that to be reflected as a conditional super type.  I might express that in Java code like:

    class Box<T>
        <when T extends Comparable<T>> implements Comparable<Box<T>> { … }

 Having a bootstrap that comes up with the list of supertypes as  function of the type parameters allows such things to be represented.  

> Relationship between: raw type, template class, erased species

There are two questions embedded here: 
 - are the above all types, and if so what is their subtyping relationships, 
 - what is the relationship between the _members_ of these various types

Our working story is that in the VM, there are _class_ and_species_ types.  From a template class, we derive a class type and a mechanism for deriving the species types from their type parameters.  The compiler translates uses of wildcard and raw types as the class.  The Class is a super type of all the species of that template.  

Separately, the compiler ensures (through the translation model) that the _class_ has all the same members as the erased species.  So for any member m in the erased species, call sites / access sites for c.m will link, where c is of the class type.  

> proposal is that the template class is not instantiable

Yes but … 

Old code (and maybe new) will have `new Foo` byptecodes in them; we’d like to redirect these to instantiate the erased species.  

> Request from vm runtime
> in the specialized class file, we need both the name/UTF8 string AND the Constant_Class to have a place to store the passed-in resolved type parameter

Yes, definitely.  M3 sidestepped this as a prototyping move, but we need to meet this head-on, and its a nasty problem.

More information about the valhalla-spec-observers mailing list