> On Jun 13, 2023, at 12:17 PM, Remi Forax <[email protected]> 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.)

Reply via email to