It starts with a bang ends with a quote

Remi Forax forax at univ-mlv.fr
Tue May 21 08:09:59 UTC 2024


Hello,
I recently tried to convince myself that using a type annotation (the bang '!') was the best way to do type specialization at langage level but I still find it awkward.

There are several reasons why using a bang to ask for type specialization does not work well with the rest of the design of value types.

The first argument is that value types is a runtime construct, in term of typing and code generation, a value type is undistinguishable from an identity type, only when the code is run, one can tell the difference. On the other hand, a bang is a type construct, a bang change the typechecking (change the type inference) and has a side effect on the generated code.
So there is a mismatch here. The obvious problem from that mismatch is that a bang will record if a value type is a value type at typechecking time while the corresponding class may not be a value type at runtime. We have the same problem with the Preload attribute, so it's not a major problem.

The second argument is that bang is a use-site declaration (new ArrayList<Point!>()), unlike a value class which is declared at declaration site. We know that use site declarations make the language harder to use. We tried in the past to not introduce features that uses use-site declaration (const?) or in case of wildcards (aka use site variance), the rational was that not all users are exposed top wildcards, only library devs need to declare them. Using use-site declarations should be avoided if possible.

The third argument is that it adds a complexity to the model that we may not need. In a langage like C#, a list of value type is a flatten list, a list of identity type is not flatten, there is no way to ask for a list of value types that is not flatten. One advantage of the bang is that it is easier to retrofit the relationship between a wrapper type and its primitive type, a primitive type like int being (mostly) an Integer!. But wrapper types can be seen as special cases, we may not want all value types to behave like primitive types or wrapper types depending on the user choice.

For the parametric VM, I think we should first try to implement a simpler model where all value types (with implicit constructor) are flatten (if the field/array is tagged as such) and only move to a use site model if there are performance issues.

Here, I describe the quote model, which is the bang model without use-site declaration.
Let's introduce the sigil ^ (quote) that can be used only on a type variable or an array of type variable.
A field declaration can use T^ or T^[] as type. When an array is created, new T^[12] can be used otherwise the class of the type argument is not flatten.

Collections like the implemntation of List.of() or ArrayList can be retrofitted to create their arrays with a quote, the only problem is that the return value of List.set() can be an empty value type instead of null, but the return value of List.set() is rarely used so it should not be a big issue in practice. Map.get() can return null which is not a problem because T is nullable, only T^ on field is not.

What we are loosing here is the
- calling convention adaptation may be harder for the VM
- wrapping classes like java.lang.Integer, etc should *not* have an implicit constructor, int == Integer+implicit constructor when using List<int> and List<int> has a boxing convertion with List<Integer>.

I think we should try the quote model first, evaluate it before deciding to move or not to the bang model.

regards,
Rémi


More information about the valhalla-spec-experts mailing list