> Rust developers can fluently switch and convert between conrete `Result<T, SomeErrorEnumeration>` and `Result<T, dyn Error>`
That's something different, since both cases tell you that errors might occur.
In Java we can do the following:
public int concreteChecked() throws FileNotFound {
if (bar) throw new FileNotFound();
return 42;
}
public int polymorphicChecked() throws Exception {
if (bar) throw new FileNotFound();
return 42;
}
public Either<FileNotFound, int> concreteEither() {
return bar? new Left(new FileNotFound()) : new Right(42);
}
public Either<Exception, int> polymorphicEither() {
return bar? new Left(new FileNotFound()) : new Right(42);
}
public int unchecked() {
if (bar) throw new RuntimeException(new FileNotFound());
return 42;
}
I think your 'Result' examples are like the third and fourth examples above: using a sum type, differing by whether the error is more/less specific.
The first and second use checked exceptions, again differing in whether the error is more/less specific. Importantly: these will refuse to compile if we don't have 'throws ...' in their signature.
The last example uses an unchecked exception: if we throw 'RuntimeException' (or a subclass), we don't need to put 'throws ...' in the signature, and hence the compiler won't keep tell us to put 'catch' block anywhere.