Money for Nothing, ...
Dan Smith
daniel.smith at oracle.com
Wed Jun 14 17:34:08 UTC 2023
> On Jun 13, 2023, at 12:17 PM, Remi Forax <forax at univ-mlv.fr> wrote:
>
> Hello,
> currently, it's not possible to write a lot of generics sealed type because Java has no way to denote the bottom type.
>
> By example, if a Result can be either a Success or an Error, we want to be able to write this kind of switch
>
> public static void main(String[] args) {
> Result<String, IOException> result = ...
> var val = switch(result) {
> case Error<IOException> error -> 1;
> case Success<String> success -> 2;
> };
> }
>
> But i do not see a way to do that without introducing a way to denote the bottom type (named "Nothing" here)
>
> sealed interface Result<T,E extends Exception> {}
> record Error<E extends Exception>(E error) implements Result<Nothing, E> {}
> record Success<T>(T value) implements Result<T, Nothing> { }
>
> Nothing being the return type of a method that either never terminate (by example, using a for(;;)) or always throw an exception.
>
> So, should we add Nothing to Java or is there another way to model this kind of sealed types ?
You're looking for a generics feature we don't have: a single object that implements multiple parameterizations of the same superinterface.
That is, you want:
Success<String> <: Result<String, IOException>
Success<String> <: Result<String, RuntimeException>
Success<String> <: Result<String, Throwable>
...
Academics have explored this, but it's a pretty deep change to how Java handles generics.
(A "bottom type" doesn't quite do it, because it needs to be paired with declaration-site variance.)
What the language requires instead is something like:
sealed interface Result<T,E extends Exception> {}
record Error<T,E extends Exception>(E error) implements Result<T,E> {}
record Success<T,E extends Exception>(T value) implements Result<T,E> { }
(Or rethinking whether this degree of generality is really necessary for the problem.)
More information about the amber-spec-experts
mailing list