Money for Nothing, ...
Robbe Pincket
robbepincket at live.be
Wed Jun 14 19:10:03 UTC 2023
David Alayachew
Wed Jun 14 13:00:06 UTC 2023
> Hello Rémi,
>
> To start off, Nothing is only going to take you a short distance. Nothing works decently enough for the type T. But for the Exception, Nothing will not work as a type parameter because the type parameter it is supposed to be matching is E, and E extends Exception. Nothing does not extend Exception (presumably), and even if it did, this would be a constantly growing problem that we do not want to put into the language. What if you need R to extend List\<String>, for example?
This is a flawed understanding of the question that was asked. A 'Bottom type' ('Nothing' here) is a type that extends every other type and is not instantiatable.
Brian Goetz
Wed Jun 14 17:50:53 UTC 2023
> [...]
> What you are probably reacting to here is "but why does Fail have to say T, it doesn't use it." And the answer is: "get over that, and then you're done."
>
> You are trying to invent a new generics feature to avoid putting a `T` you don't use in your Error declaration. But that T (and maybe E) are needed to unify the two under Result<T,E> -- just like in the second Haskell example above.
A valid reason in my opinion to want a `nothing` type is that it would solve the issue of unchecked casts your solution will introduce.
```
static Result<String> getContentOfFile(Path path) {
// simple mock implementation
if (!Files.exist(path)) {
return new Fail<>(IOException("..."));
} else {
return new Succ<>("Data");
}
}
static Result<List<String>> getLinesOfFile1(Path path) {
return switch(getContentOfFile(path)) {
case Succ<String>(var contents) -> new Succ<>(contents.lines().toList());
case Fail<String> error -> (Result<List<String>>) error; // requires unchecked cast
}
}
static Result<List<String>> getLinesOfFile2(Path path) {
return switch(getContentOfFile(path)) {
case Succ<String>(var contents) -> new Succ<>(contents.lines().toList());
case Fail<String>(var error) -> new Fail<>(error); // requires redundant allocation
}
}
```
One maybe slightly better solution is to introduce an `into` method on `Fail` to hide the cast
```
record Fail<T>(Throwable t) extends Result<T> {
public <R> Fail<R> into() {
return (Fail<R>)this;
}
}
static Result<List<String>> getLinesOfFile3(Path path) {
return switch(getContentOfFile(path)) {
case Succ<String>(var contents) -> new Succ<>(contents.lines().toList());
case Fail<String> error -> error.into();
}
```
In the end, once we get value types, `getLinesOfFile2` wont really be an issue, (maybe someone even makes an extra optimization for sealed types where all subclasses are value types). Additionally, like Dan Smith said, a bottom type would only be useful here if have declaration-site variance, which we don't have (*yet*).
Kind regards
Robbe Pincket
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-spec-observers/attachments/20230614/057c6d14/attachment.htm>
More information about the amber-spec-observers
mailing list