Totality over generics

Remi Forax forax at univ-mlv.fr
Fri Sep 24 16:58:56 UTC 2021


----- Original Message -----
> From: "Per Minborg" <minborg at speedment.com>
> To: "amber-dev" <amber-dev at openjdk.java.net>
> Sent: Vendredi 24 Septembre 2021 18:19:40
> Subject: Totality over generics

> Hi,

Hi Per,

> 
> What if we could do something like this in some distant future:
> 
>     <T extends Integer | String> int eval(T t) {
>         return switch (t) {
>             case Integer i -> i;
>             case String s -> Integer.parseInt(s);
>             case null -> 0;
>             // Totality
>         };
>     }
> 
> 
> Already today , an equivalent second layer of sealed wrapper classes
> could achieve the same goal but with much more ceremony. Of course,
> there are also overloads but how cool is that?

The problem is that this is not compatible with how a OR between types works in Java,
By example, if you use ?: between a String and an Integer, you get the common super types between String and Integer, something like Object & Comparable<? extends Comparable<?>> & Serializable but not String | Integer.

So a code like this does not compile
  Integer i = 3;
  String s = "foo";
  Integer | String value = (condition)? i: s;  // oops

You can say that this is a bug with ?:, but a method like <T> T choose(boolean cond, T value1, T value2) will infer T the same way.

So what you are proposing is cool but we can not doing it without breaking a lot of existing codes.

The reason it was done that way is that if String and Integer both have a method with the same signature, there was no way in the bytecode to call that method apart if the method was declared one of the common super type. So instead of allowing the type String | Integer but not allow to call all methods on it, it was decided to replace String | Integer by the common supertypes because with these types we can generate the correct bytecode.

Since Java 7, we can now use the bytecode instruction invokedynamic to dynamically call the method of Integer or the method of String,
so this is now technically possible to implement String | Integer on the JVM.

Scala 3 introduce the concept of | between types, this is one of the reasons why Scala 3 is not compatible with Scala 2 (Scala 2 like Java uses the common supertypes).

Maybe someone may come in the future with a way to represent String | Integer which is backward compatible in Java. One idea is to try to keep String | Integer but convert it to the common supertypes if necessary. But it's research work that as far as i know has never been done.

> 
> Best, Per Minborg

regards,
Rémi


More information about the amber-dev mailing list