Live data from Hacker News

Avoid exception throwing in performance-sensitive code

lemire.me

191–200 of 243 posts

Re: Avoid exception throwing in performance-sensitive code

#191

This is one of my basic interview questions to candidates and it is amazing how many people have no idea how exceptions work or how much they cost. Back in 2005, I was involved in a replatforming of the legacy COBOL and TRANSACT HP3000 mainframe codebase to the modern system. The code was transpiled into an [unholy mess of] C# and ASP.NET. The Transact code was extremely procedural and had mainframe forms interspread…

That seems exceptionally bad!

They did try though.

Re: Avoid exception throwing in performance-sensitive code

#192
post #8

Different languages have different exception handing optimizations. A Java version of the example can run very slow or very fast, depending on how clever you are. When a new RuntimeException is thrown half the time, the example runs about 650 times slower when compared to a function which adds up the integers without using exceptions. If I define an exception subclass which doesn't fill in the stack trace, then it ru…

Moreover, different languages implement the exception handling differently. The article focuses on C++, which has a notion of object destructors (most – but not all – programming languages don't have the destructors). Implications for the exception handling are manyfold: upon an entry into a «try» block, a C++ compiler has to account for all objects created at the method (or function) scope up until this point and re…

It also depends on the implementation, for example VC++ can ping back on Win32 structured exception handling, which other OSes don't have.

Re: Avoid exception throwing in performance-sensitive code

#193

Earlier quoted context omitted.

I think what Java got wrong was allowing catching unchecked exceptions. If Java had only allowed recovering from checked exceptions, it would have been a very similar experience to Rust's Result and panic. Instead, the trend was to avoid using checked exceptions at all, which perpetuated the crazy situation we're in where library code can suddenly abort and the author shrugs and says "shoulda read the docs".

Java got wrong with the concept of checked exceptions. They're not needed. Python, C++ or JavaScript exceptions are totally fine. And checked exceptions bring nothing but issues. The only thing that I'd add to the unchecked exceptions is noexcept with compile-time checking. Something along the lines: 1. You can declare method as `nothrows`. Compiler will ensure that no exceptions are thrown (`java.lang.Error` can sti…

Java always gets the blame, yet the concept of checked exceptions was introduced by CLU, adopted by Modula-3 and C++, before it came to Java.

And even though C++ dropped exception specifications, they still kept the difference between might throw anything or doesn't throw at all, and there is also the paper to reintroduce them Swift style.

Re: Avoid exception throwing in performance-sensitive code

#194

Earlier quoted context omitted.

Stack traces. The information required to build a stack trace is deliberately kept off the critical path so it doesn't impact performance during normal operation, but that means that building a stack trace requires going out and fetching the debug symbols and correlating them. Without stack traces, exceptions are just a type of goto.

While you are absolutely right that collecting stack traces is an extremely costly operation, it's not the only problem. For example, in C++, which doesn't collect any kind of stack trace, throwing an exception is still ~1 order of magnitude slower than returning a value through all the layers. Note that this cost only happens when the exception is thrown; exception-based code is otherwise slightly faster than `if re…

Ah, fair, I don't have a lot of experience with C++. My answer was based on Java, which from the benchmarks I've seen doesn't suffer from any performance hit when you use a static exception object with no stacktrace.

Re: Avoid exception throwing in performance-sensitive code

#195

Earlier quoted context omitted.

My point is that this is in no way different from any other class of errors, _except_ in those cases where it is. It's practical to assume all errors are handled like this, because this catch all needs to exist anyway. And unless you have _very specific needs_, this can be automated.

I think conflating these two into one paradigm is worse. The catch-all (exceptions) style is nice only for a few very specific cases, like the request handler example. Everywhere else I want to either bubble up (like exceptions, but Result and ? sugar is as good or better), OR I want to handle the error. For the latter case, exceptions are not good at all.

IMHO, quite often when you're tempted to handle an error, you're either wrong to do so, or in some kind of infrastructure glue code. A request handler, a task executor, a strategy chain, a retry loop, you name it. And this code needs to deal with both classes of errors anyway to be bugfree.

Re: Avoid exception throwing in performance-sensitive code

#196

Earlier quoted context omitted.

I think what Java got wrong was allowing catching unchecked exceptions. If Java had only allowed recovering from checked exceptions, it would have been a very similar experience to Rust's Result and panic. Instead, the trend was to avoid using checked exceptions at all, which perpetuated the crazy situation we're in where library code can suddenly abort and the author shrugs and says "shoulda read the docs".

Java got wrong with the concept of checked exceptions. They're not needed. Python, C++ or JavaScript exceptions are totally fine. And checked exceptions bring nothing but issues. The only thing that I'd add to the unchecked exceptions is noexcept with compile-time checking. Something along the lines: 1. You can declare method as `nothrows`. Compiler will ensure that no exceptions are thrown (`java.lang.Error` can sti…

I disagree that standard exceptions are fine for recoverable errors.

Recoverable error states are part of your function's interface. Languages with exceptions make this implicit: in order to know how to interface with a function's error states you have to go digging through the docs, which hopefully document the exceptions it throws. If they don't, then you either have to trace the entire call tree or just wait for the library to throw something so you know what you're supposed to be catching.

On the other hand, if a language requires that recoverable errors be documented in the function signature (either as a checked exception or error-as-value), you know that you're either handling the exceptions or intentionally letting them propagate. There are no surprises at runtime because the set of all possible error states is known statically.

Re: Avoid exception throwing in performance-sensitive code

#197
post #84

Earlier quoted context omitted.

I think what Java got wrong was allowing catching unchecked exceptions. If Java had only allowed recovering from checked exceptions, it would have been a very similar experience to Rust's Result and panic. Instead, the trend was to avoid using checked exceptions at all, which perpetuated the crazy situation we're in where library code can suddenly abort and the author shrugs and says "shoulda read the docs".

> where library code can suddenly abort and the author shrugs and says "shoulda read the docs". In see no difference. Except for the fact that you don't have the stacktrace (in Go), and unroll the Stack manually. In any case, there'll be a generic catch (whatever you call it) on the top level of your daemon to recover from the failed request and handle the next.

The difference is that the error states are explicit rather than implicit. The function's signature tells you what the possible errors you'll need to handle are, so you don't get caught off guard at runtime.

As for stack traces: checked exceptions are semantically almost identical to error-as-value but they do give you a stack trace. They give you all the static guarantees of error-as-value plus the benefit of being able to know where the error came from.

Re: Avoid exception throwing in performance-sensitive code

#198
post #65

Earlier quoted context omitted.

I think what Java got wrong was allowing catching unchecked exceptions. If Java had only allowed recovering from checked exceptions, it would have been a very similar experience to Rust's Result and panic. Instead, the trend was to avoid using checked exceptions at all, which perpetuated the crazy situation we're in where library code can suddenly abort and the author shrugs and says "shoulda read the docs".

> I think what Java got wrong was allowing catching unchecked exceptions. If Java had only allowed recovering from checked exceptions, it would have been a very similar experience to Rust's Result and panic. > Instead, the trend was to avoid using checked exceptions at all Java's type system was far too weak for that to be at all practical. Early Java not only didn't have first-class functions, it didn't even have ge…

That's fair. Lack of inference is also a huge problem with Java's checked exceptions.

My point is less that Java could have done this differently with the other type choices that they made and more that it's a shame that Java's implementation of checked exceptions has poisoned the concept for so many. I think a language with strong type inference and a checked exception mechanism would be better than Rust's Result type because you get the stack trace.

Re: Avoid exception throwing in performance-sensitive code

#199
post #8

Different languages have different exception handing optimizations. A Java version of the example can run very slow or very fast, depending on how clever you are. When a new RuntimeException is thrown half the time, the example runs about 650 times slower when compared to a function which adds up the integers without using exceptions. If I define an exception subclass which doesn't fill in the stack trace, then it ru…

Why not just use a branch friend, why not? None of the uses you listed is faster but at best case is "equivalent" why avoid it at all?

I know the article is about performance but from a sheer programmjng perspective brqnches are there for a reason.

Re: Avoid exception throwing in performance-sensitive code

#200
post #94

Earlier quoted context omitted.

Stack traces. The information required to build a stack trace is deliberately kept off the critical path so it doesn't impact performance during normal operation, but that means that building a stack trace requires going out and fetching the debug symbols and correlating them. Without stack traces, exceptions are just a type of goto.

What about dynamic languages? Are they always collecting the stack and keeping it into some exception object that the exception can grab the data from at any time? And if that's the case wouldn't it always be slow regardless of raising or not ?

A performant dynamic language won't bundle the debug symbols either, so my assumption would be that the performance of an exception would still be bad.
Post reply on HN