Also, regarding "compiler is likely to produce more efficient code.", benchmarks have shown that exceptions are generally faster : http://nibblestew.blogspot.com/2017/01/measuring-execution-p...
Also, regarding "compiler is likely to produce more efficient code.", benchmarks have shown that exceptions are generally faster : http://nibblestew.blogspot.com/2017/01/measuring-execution-p...
Not only that, but you don't have to write a ton of boilerplate to manually propagate errors back up the stack since the compiler will do that for you. And it will do it in a consistent, well-defined manner.
Not if the ecosystem supports Result types a la Rust (and others). You don't get to access the return value unless you deal with handling the error first.
Well, that's exactly what I was referring to. 80% of the time you don't / can't know what to do with the error at a given call site, so from what I could see, either people end up doing nothing and "abandoning" the error (bad) or panicking (worse). It's better to just let the error go transparently so that if someone actually can do something meaningful upper in the call stack, it's possible.
$ cd servo/components
$ rg -F 'panic!' | wc -l
276Likely a fair amount is justifiable, but things like this ? https://github.com/servo/servo/blob/master/components/script... or this https://github.com/servo/servo/blob/master/components/gfx/pl... ?
that's a really strong code smell (or at least doing a similar thing in a C++ program, e.g. calling abort() / SIGTRAP, would be, even with a signal handler, a really really really long discussion in code review)
And yes, I do think that both of these are pretty justifiable: both of these are effectively assertions, which is not unheard of in C either.
I don't like verbose error checking on every function call which is ugly and which I might forget to pass up (c-style) and I don't like exceptions which aren't expicit and which I might forget to handle locally if I wanted to.
If you're working with a `Result` type, you can pass the wrapped value up to wherever you want to/can handle it. Either way, you have to handle it. And the type checker ensures that you do.
Typed error checking as available in Rust, Scala, OCaml, ReasonML, Swift, Haskell etc, etc is a far, far better solution than exceptions. I've worked on large code bases with both. There's no comparison.
Even Java's checked exceptions are far, far better than unchecked exceptions like C++. People complain, but it's shitty coding practice not to properly handle a function that can throw (and I speak as someone who's done this and gotten badly bit by it a dozen times before I wised up).
If there's absolutely no recovery possible from an error, then yes, an exception may be acceptable. Otherwise, error values, which can be type checked, are the way to go if offered in your language.
The blog post you linked to says "Immediately we see that once the stack depth grows above a certain size (here 200/3 = 66), exceptions are always faster. This is not very interesting, because call stacks are usually not this deep (enterprise Java notwithstanding). For lower depths there is a lot of noise, especially for GCC ..." So ... not exactly "generally faster".
Also, the test is only for Linux. The same test on Windows/VC++ will probably run a lot slower ... again not "generally faster"
> The same test on Windows/VC++ will probably run a lot slower ...
By default on 32-bit, with SJLJ exceptions, that's likely. But on 64-bit windows the default exception handling (SEH) uses a similar mechanism than Linux and should have comparable performance.
AFAIK SEH in Windows calls RaiseException() which in turn causes a user/kernel mode transition, probes for exception/termination handlers, and vectored exception handlers depending on the severity. It's been a while but I'm not sure the code GCC generates in Linux is quite like this.
> Look at all the results. Even before that exceptions are more often a win than a loss.
The blog post you linked to effectively says "it depends"