"Model 2" prototype status
Brian Goetz
brian.goetz at oracle.com
Sat Aug 1 15:23:16 UTC 2015
> Thanks for the hard work on this.
> The Foo<ref> looks like a nice parallel to Foo<any> to my eyes.
Thanks!
Some more on where we're going with this. You should be able to say
"ref" wherever you can say "any", so:
class Foo<T> { ... }
becomes a shorthand for
class Foo<ref T> { ... }
(just as Foo<?> has always been shorthand for Foo<? extends Object?>.)
Also, the details of translation mean that the "all any" and "all ref"
instantiations of a type with multiple tvars are somewhat "special", so
for a type Foo<any X, any Y, any Z>, we'll probably accept
Foo<any>
as shorthand for Foo<any, any, any>
and
Foo<ref>
as shorthand for Foo<ref, ref, ref>
Since the arity is fixed and known at compile time, there's no problem
with this; there's no other logical meaning to instantiating with the
wrong number of type args.
(Note: The compiler doesn't yet support these yet.)
The details of "partial wildcards" (Foo<int, any>) are messy and we're
working on a story for them.
>
> Stephen
> On 31 Jul 2015 20:51, "Brian Goetz" <brian.goetz at oracle.com> wrote:
>
>> Over the past few months, we've been building what we call our "Model 2"
>> prototype, and incrementally checking it in. It now seems stable enough
>> for brave early adopters to check out. (You'll need to build the JDK from
>> source.)
>>
>> The previous version ("Model 1") was focused on exploring the practicality
>> of specialization on the JVM architecture we have today. The compiler
>> augmented classes with type metadata that otherwise would be erased away,
>> which could be ignored by the JVM but consumed by the specializer.
>> Specialized classes were identified using a name mangling scheme (strictly
>> an expedience for prototyping, not a long-term plan.) The class loader
>> recognizes the name mangling scheme and, if not found in the class path,
>> the class loader invokes the specializer to generate the specialized class
>> on the fly.
>>
>> With these many hacks (name mangling, abuse of class loaders), the result
>> was mixed. On the good side, it worked! It was possible to write
>> specializable generic classes and run them on an only-lightly-hacked JVM.
>> On the bad, the resulting language had a significant usability issue -- the
>> lack of a nontrivial common supertype between Foo<int> and Foo<String>.
>>
>> Of course, we didn't pursue this approach because we thought half-killing
>> wildcards was a great idea; we pursued it because it was what worked on the
>> JVM we had. So with the Model 1 prototype in hand, we set out to see what
>> could be done about providing a reasonable common supertype for all
>> instantiations of an any-generic type. (We explored a number of possible
>> mechanisms and approaches, including several that are more radical than
>> where we landed. Hopefully we will find time to write up some of these
>> roads-not-taken.)
>>
>>
>> Type variables. Type variables are divided into two categories; "ref"
>> (ordinary) and "any". Any tvars ("avars") are identified by the keyword
>> "any" at their declaration site (for both generic classes and generic
>> methods). If a type variable is not modified by "any", it is implicitly an
>> ordinary tvar, and treated just as in Java 8.
>>
>> class Foo<T> { ... } // T is an ordinary tvar
>> class Bar<any T> { ... } // T is an avar
>>
>> Class hierarchies can be any-fied from the top down. So it's OK to do:
>>
>> class A<any T> { ... }
>> class B<T> extends A<T> { ... } // T is an ordinary tvar here
>>
>> but not OK to do:
>>
>> class A<T> { ... }
>> class B<any T> extends A<T> { ... }
>>
>> The rationale for this should be clear enough; specializing a class
>> entails specializing its superclasses, and if the superclass is not
>> specializable, this won't work. (Alternately, you can interpret "any T" as
>> a union bound ("T extends Object | value"), and its OK to use a narrower
>> bound than your supertype, but not a wider one.)
>>
>>
>> Restrictions on avars. Some operations that are allowed on ordinary tvars
>> are not allowed on avars, such as assigning a T to an Object, assigning
>> null to a T, etc. These have not changed from Model 1.
>>
>>
>> Wildcards. The big change in Model 2 is the addition of support for
>> wildcards over avars. The problem with wildcards has two facets;
>> translational (how do we represent a wildcard type over avars in bytecode?)
>> and interpretation (Foo<?> has always been a shorthand for Foo<? extends
>> Object>; on the other hand, the "intuitive" intepretation of Foo<?> is "any
>> instantiation of Foo.") The translational issues require some help from
>> the JVM to solve (not yet implemented in the prototype.) The interpretive
>> issues are subtle. While we explored trying to automatically interpret
>> Foo<?> according to the common user intuition, this ran afoul of numerous
>> compatibility issues.
>>
>> So, where we landed is: just as one must specify any-ness at the
>> declaration site for a type variable, one must do the same for a wildcard
>> (which is essentially declaring an anonymous type variable.) So there are
>> two forms of wildcard:
>>
>> Foo<ref> -- describes any reference instantiation
>> Foo<any> -- describes any instantiation
>>
>> and Foo<?> will be retconned to mean Foo<ref>.
>>
>> Raw types. Raw types have not changed at all from Java 8. As such, they
>> are limited to reference instantiations.
>>
>> The upshot of this is we can achieve perfect source compatibility; the raw
>> type Foo and the wildcard type Foo<?> continues to mean exactly what they
>> always did.
>>
>>
>> As a proof of concept, I've checked in a limited version of Streams
>> (java.anyutil.Stream) that has been ported to the new model. (Some things
>> are still not hooked up yet, but the basic functionality for Stream<any T>
>> works.)
>>
>>
>> The Model 2 approach needs some (targeted) help from the VM, which is not
>> yet in place. (Specifically, protected/package methods in interfaces, and
>> some help for access to private members across specializations of the same
>> class.) Until we have this, protected/package methods in anyfied classes
>> will be problematic.
>>
>> There are also some compiler limitations, the most significant of which is
>> that inner classes don't yet work as instantiations of anyfied classes; you
>> have to refactor the inner class to a static named class. (There's no
>> fundamental issue here, its just not done yet.)
>>
>> Most helpfully, the latest IntelliJ has some early support for anyfied
>> generics! (It's not perfect, but its been really helpful -- thanks guys.)
>> Select language level "X" (for experimental) and it will mostly deal with
>> any-tvars and any-wildcards, instead of painting your whole program red.
>>
>>
>> We'd like to get feedback from people *using the prototype* to anyfy their
>> own code. (I'm sure people have a zillion "why did you / why didn't you"
>> questions; we'll try to get to those in a writeup.) I'll also be putting
>> together a writeup on the translation strategy (though brave explorers can
>> and surely will reverse engineer this with javap before this happens.)
>>
>>
>>
More information about the valhalla-dev
mailing list