On Wednesday, 10 June 2015 at 19:56:00 UTC, Dave wrote:
I usually agree that the more restrictive option should be the
default, but exceptions is... well... the exception. The whole
point of the exceptions system is to limit the number of
points where you need to worry about something going wrong to
the place where it happens and the places where you want to do
something special with it.
The point of exceptions is to communicate errors and where they
originate. As long as this is respected, then I am not following
your complaint.
you have to care about the exception at every single point in
between.
That's the point. If you don't annotate the function (with a
throw keyword for instance), then you are forced to catch and
handle the exception. If you annotate it (saying this function
will throw), no catch is needed, but at least you are
communicating to the next layer that
this code *does* have errors that should be accounted for.
nothrow by default means you can't do that
Actually no guarantees by default means you can't do what I
explained above.
The promise of exceptions isn't to not have to specifically
handle errors in every layer - it's to not care about exceptions
in every layer. I don't want to pass the annotation in each and
every intermediate layer - I want only the throwing layer and the
catching layer to acknowledge the exception's existence. The
middle layers should be written like there is no exception, and
when there is one, they will simply fail and let RAII to
automatically do the cleanup.
I've programmed enough Java to know how harmful
nothrow-by-default is. It doesn't really guarantee the functions
not annotated as throwing won't crash - only that if they do
crash there is nothing you can do about it. This mechanism is so
easy to bypass in harmful ways(catch and rethrow something that
doesn't need annotation(like Error), or terminate the process
with a special exit function), and annotating the layers all the
way up is so cumbersome(and sometimes impossible - when you
override functions, or pass delegates) that this mechanism tends
to encourage to bypass it, which harms the debugging.
Of course, nothrow as the optional annotation is a different
syntax for the same semantics, so it suffers from the same
drawbacks but it has the benefit of seldom being use therefore
seldom getting in your way. Which leads me to the final
conclusion - there shouldn't be nothrow, not by default and not
as special annotation!
(I'm not talking about D here - this isn't worth the code
breakage - but generally on programming languages)
If it's an error that the caller needs to know about - make it
part of the return type. If it doesn't need to know about it -
throw an exception and let someone up the line handle it. Rust
got it right - though they made it a bit cumbersome to catch
`panic`s. Why would I need to catch panic? To display them nicely
to the user(don't just dump to stderr - pop up a window that
apologizes and prompts the user to email the exception data to
the developers) or to rollback the changes(yes, there was an
irrecoverable error in the program. That doesn't give me the
right to corrupt user data when I can avoid it). But the point is
- you can either handle it or ignore it. The "sign here and we'll
pass it on" bureaucracy is not benefiting anyone.