You can easily implement a feature which lists all possible exceptions that a specific function raises.
Java has a feature called checked exceptions that ensure that you handle all possible exceptions in your program, although admittedly this feature is annoying. Another language called Nim[1], that is in fact a pretty good Go alternative, offers a similar feature[2]. But in Nim it's opt-in and the documentation includes information about each procedure and the exceptions it raises, this is shown by the `raises` pragma where `raises: []` means that no exception is raised. For example, you can easily see that `parseInt` may raise a `OverflowError` or a `ValueError` in the documentation[3] whereas `normalize` doesn't raise anything[4]. This information is inferred by the Nim compiler automatically.
In my opinion this is the best of both worlds, because when your program does crash, you get a nice stack trace that is just as informative as Python's stack traces and you always know the exceptions that each procedure may raise. Here is an example stack trace from a compiler crash:
> Java has a feature called checked exceptions that ensure that you handle all possible exceptions in your program, although admittedly this feature is annoying.
I think it's mostly annoying because checked exceptions were used badly in the early years of Java, so there are methods which throw loads of unrelated exceptions which have to be handled separately. Better design of exception hierarchies, and the availability of multi-catch, makes this quite a bit better.
Although it's recently got worse again because none of the shiny new stream stuff supports lambdas which throw checked exceptions. You have to either stick to unchecked exceptions and lose type safety, or probably better, rotate the exceptions sideways in type-space and use an Either:
> I think it's mostly annoying because checked exceptions were used badly in the early years of Java, so there are methods which throw loads of unrelated exceptions which have to be handled separately.
I see that as a secondary issue, I feel the primary issue of checked exceptions is that handling and manipulating them is a terrible experience and even today I don't believe you can be generic over checked exceptions (though I could be wrong).
> Although it's recently got worse again because none of the shiny new stream stuff supports lambdas which throw checked exceptions.
It's not new though, the type-level facilities lambdas use simply don't allow for that. That's been an issue since generics were added, and even since the original release of Java.
Checked exceptions can only go through stack frames which specifically knows about them. And that, I think, is why they're such an awful experience and a failed experiment.
I don't think handling and manipulating checked exceptions is a terrible experience. Specifically, i don't think it's worse than using an Either, and as far as i know, that's the only other way to safely handle methods which can fail. The other options get better ergonomics by sacrificing safety, which isn't okay.
You can be somewhat generic over checked exceptions. This is okay:
@FunctionalInterface
interface RiskyGetter<T, E extends Exception> {
public T get() throws E;
}
This is not:
public <T, E extends Exception> T get(RiskyGetter<T, E> getter) {
try {
return getter.get();
} catch (E e) { // <-- can't catch a type parameter
e.printStackTrace();
return null;
}
}
So you have to both throw and catch concrete exception types, but you can have them pass through layers of generic code in between. It's not perfect, but it's something.
As a result, the streams stuff absolutely could have been written to handle exceptions. The standard Function interface could have been defined as throwing an exception, and the terminal operations could have thrown it on. Could, but i'm not saying should - the additional complexity of the interfaces would have been annoying, so the flexibility would not have been free.
> Specifically, i don't think it's worse than using an Either, and as far as i know, that's the only other way to safely handle methods which can fail.
`Either`s can be nested, put in lists, passed as arguments, and pretty much everything else you would expect from first-class values. Checked exceptions can't.
Java has a feature called checked exceptions that ensure that you handle all possible exceptions in your program, although admittedly this feature is annoying. Another language called Nim[1], that is in fact a pretty good Go alternative, offers a similar feature[2]. But in Nim it's opt-in and the documentation includes information about each procedure and the exceptions it raises, this is shown by the `raises` pragma where `raises: []` means that no exception is raised. For example, you can easily see that `parseInt` may raise a `OverflowError` or a `ValueError` in the documentation[3] whereas `normalize` doesn't raise anything[4]. This information is inferred by the Nim compiler automatically.
In my opinion this is the best of both worlds, because when your program does crash, you get a nice stack trace that is just as informative as Python's stack traces and you always know the exceptions that each procedure may raise. Here is an example stack trace from a compiler crash:
1 - http://nim-lang.org2 - http://nim-lang.org/docs/manual.html#effect-system-exception...
3 - http://nim-lang.org/docs/strutils.html#parseInt,string
4 - http://nim-lang.org/docs/strutils.html#normalize,string