Attendees: Remi, Tobi, John, Dan Smith, Frederic, David Simms, Victor 
Rudometov, Karen

AI: Karen: send out ways in which value types can become null
AI: Dan: send out summaries/tradeoffs of nullability strategies

corrections/clarifications welcome

I. Value Type upcoming plans?
Remi would like to see a release without waiting for reified generics.
We are all in agreement about phasing:
   proposing: 

step 1: EA binaries that support erased generics
       - need agreement on how to handle nullability
with nullable value types - to get feedback/validation on this approach
step 2: Preview with language support with erased generics

farther future: support for reified generics/generic specialization.

II. Nullability - the key open design issue for our next step

Assumptions we now all agree on: based in part from user feedback from LW1 - 
many thanks!
1. To support erased generics we need nullable value types
2. From a JVM perspective we need the default for value types to be the same as 
for Object, i.e. nullable,
i.e. LPoint; in a vm descriptor is nullable if Point is a value type.

Tradeoffs from the JVM level:
   backward compatibility with erased generics: which requires nullable value 
types 
   JIT optimizations: need null-free value types

There are additional language-level tradeoffs such as exposure to syntactic 
complexity.
It is a language design choice what the nullability default is for value types 
at the source level.

Karen clarified that for LW1: javac rejected nulls for any value types, the jvm 
implementation decoupled value
type consistency from the nullability check and has runtime null checks. So we 
need to move beyond this
mismatch.

Remi:
Is nullability of value types declaration-site or use-site?

John:
Qualitative difference between local type checking and multiple compilation 
units. e.g. if nullability can not be constrained locally, it may require a 
dynamic check.

LW1 taught us:
  1. fields and array elements: flattenable or not - decision needs to proceed 
regardless of the static knowledge of callers
  2. Analogously, method calls, implementation artifacts such as vtables, need 
design constraint similar to heap storage,
      i.e. need to make decisions regardless of static knowledge of callers

Generics breaks assumption that Value Types attribute can be used to assume 
that all value types are non-nullable.

Consider concept of Constraints on Descriptors.
  We don’t want new descriptors with new rules.
  We want LDescriptors with a rider which only added constraints, no expansions

LW1 showed us that runtime checks can cover many value type nullability checks. 
The ValueTypes attribute
does not cover generics or value-based-class migration.

Optimizations unlocked for value types (ed. note - that are not null)
   - flattenable
   - method calling convention
Both are global contracts

Need side channel information such as ValueTypes attribute or additional 
information on descriptor.
We need finer-grained nullability information to reduce the requirement on 
cross-compilation consistency.

“find the primitive” exercise:
How do we describe a reference to a value type as nullable or non-nullable

To reduce friction with generics and erasure - changed idea - need to have the 
default for new types be nullable.
There are also some wormholes in our value type consistency checking, e.g. 
MethodHandles and we need to reify
a global contract.

Propose that we reify a first class descriptor
  - which is more future proof than QTypes

vision: Add constraints as riders to explicit types. This is extensible
This provides a predictable requirement and can be also used by specialized 
generics, for language design and 
migration design.

Example for specialized generics: List<ComplexDouble> != List<ComplexFloat>
What if we continued to use List as an interface, and used a descriptor to add 
constraints

See Type Operators JEP (ed. note: JDK-8204937 )
We might want to phase this in
Frederic is also exploring a proposal to add suffices to type descriptors, e.g. 
for nullability

Karen: Note that a key benefit of using descriptors is the granularity they 
offer, not at the class file level,
that allows for JIT optimization and backward compatibility in the same file

Remi: would prefer a side table

Karen: need descriptor for field and method declaration and access
   note: array creation will need enhancing

Frederic: anewarray today only has Class_info for the element, so needs 
extending
   One approach is to extend a small number of bytecodes to operate either on a 
Class_info or on a reference

John: proposing extending Class_info to support descriptors

Remi: type annotation on code
  e.g. want method attribute for bytecode

John: channel null-rejecting/null-accepting in 
1) descriptor vs.
2) ValueTypes attribute
Descriptor is more localized
note: no one wants to use the type annotations approach

Descriptor approach:
  extensible mechanism
  Type with a tail: constraint only, restricts the value space, not extend

Verifier can check value space restrictions, and may allow some 
restricted->unrestricted conversions

Karen: let’s start with explicit conversions with exact matches for the 
verifier and evolve from there

John: generics did that, in future the verifier could handle no-op conversions

Remi: how would you express this in the java language?

John: this is a vm mechanism, that is a language choice

Remi: Would javac track nullability
John: A source processor that did not understand type constraints could rely on 
dynamic checks
Remi: concerns about leakage if stored in a local variable 
John: Var x = myMap.get() // result is unconstrained
Dan: tentatively the type system may provide a way to express nullability
John: already expresses unconstrained 
Remi: javac - objects are always nullable
John: language level take
   - want javac to assume restrict nulls for value types unless evidence to the 
contrary, e.g. calls to erased generics that
   semantically return null or explicit source decorations
  - not clear what a local variable will denote
  - might want inverted defaults for value type nullability at the source level

Remi: concern: erased generic returns null -> this could spread
   checkcast could prevent null from propagating

John:
  Clojure/Scala - have their own descriptor constraints
  could decouple with indy on checkcast

Remi: value type and nullability as separate concerns
  what about a reference type that is non-nullable from the vm point of view
John: nonnullable and value type might be the 1st use. We need an extensible 
mechanism

Remi: why not value type attribute
John: could explore value type as a descriptor extension
Remi: what if we solved this at the java level, if java wants a nullable VT, 
use erasure and checkcast?

John: Dan is exploring possible models
  Getting user back pressure - don’t take away nulls 
  Liked the trick of erasing to object
  lost the battle due to language requirements

Remi: if erase to Object/Interfaces, this is not backward compatible
   Not forward compatible either with expectations of overloading in java 
language
   Have overloading today because we don’t have Object as root for primitives 
and value types

What if we got a value from generics already erased and let java handle this?

Karen: we need to handle both erased generics and value-based-class migration

Remi: Create folks want value types, and want to retrofit existing classes - 
they don’t want to lose
sync and mutability.

ed. note: You can only pass-by-value if you have no identity and are immutable.

Karen: Descriptor contraints extensibility could provide additional use cases 
for optimization, such
as “frozen” or just identity less. We chose value types as a sweet spot that 
solves a number of use
cases and can be optimized.

Additional discussion on overloading

John: one goal is to migrate List<valuetype> to a reified generic. We could do 
dynamic checking and speculating,
it is more performant to do reified generics
The nullability contract of a container impacts the implementation of the value 
space

Remi: If map.get() were to return a value type, we don’t see the null until we 
publish or invoke a method
John: with the more complex descriptor model, getfield has fewer runtime checks
Karen: goals is to have information for javac, verifier and runtime so that 
javac can have the same contract for
nullability and NPEs that we have today for ClassCastExceptions - i.e. if your 
code compiles without warnings you will not get a runtime CCE should apply to 
NPEs (or ArrayStoreException)

Remi: concern about heap pollution
  Guava has an unsafe cast to take a public static method()Object and return 
anything
John: we should distinguish between heap pollution and the far riskier other 
levels of unsafe

Remi: what if javac could handle erased generics without descriptors? And 
require a null check before a null
escapes
Karen: we would lose the value-based-class migration
John: If Remi is describing: if we only had the ValueTypes attribute and one 
descriptor and the language folks handled any null erased to Object, then we 
have to check for wormholes, such as MethodHandles or other cases in which the 
ValueTypes attributes differ.
Karen: I don’t see a language solution for value-based-class migration. Note 
also that there are multiple ways to get null, not just through bytecodes.
Remi: What if we had a small jdk-only list of corner cases for migration?
Karen: Dan has pointed out and I agree with him that many users are going to 
want the benefits of migrating to value types, and even in the JDK, there are 
already experiments beyond the small list of existing VBCs.
   If we have a way to avoid corner cases that would be a much more 
maintainable design.
Remi: But if sync and == don’t work there is no way to migrate most classes. 
And if value-based-class properties are not enforced, there is no guarantee 
they are followed.
Karen: recognize that - we will be offering a flag to check identity - one for 
javac lint and one for runtime.
Karen: note also that for erased generics we have two null issues
   1. returning null 
   2. passing array in and writing null
   goal is a javac warning before a runtime NPE

Remi: Can we find a way to solve this at the language level, javac can give a 
warning but the vm doesn’t need to know
  Kotlin has 2 types: nullable and nonnullable with compiler enforcement
Frederic: clarification Kotlin has references that are nullable or not, not 
types

John: Had been exploring using erasure for the nullable value type case and the 
ValueType attribute implying null.
  Dan is exploring possible alternative translation strategies with different 
approaches to distinguish a non-nullable value type from an old erased value 
type

Remi: concern is that if we solve nullability here for value types, we may miss 
something for the bigger nullability picture. 
.net got this wrong and requires too much complexity with little user benefit.
Longer-term: want non-nullable 
Exploring how to solve value types and reified generics without involving the 
vm.

John: would be happy to defer a nullability vm feature until reified generics 
or after
Remi: wants longer-term non-nullability, e.g. for Strings, with vm optimizations
.net added too much source level line noise for little benefit

Karen: we need to handle nullability for value types for more than just erased 
generics. We have mentioned value-based-class migration. There are 8-9 
different ways in which value types can become null at runtime.

AI: Karen - send nullability cases

Dan: Will send out a description of current options we are exploring to handle 
requirement for null-accepting and null-rejecting value types.








   


   

Reply via email to