Live data from Hacker News

Avoid exception throwing in performance-sensitive code

lemire.me

81–90 of 243 posts

Re: Avoid exception throwing in performance-sensitive code

#81

Earlier quoted context omitted.

"Exceptions should be... the exception." :)

The problem is exceptions have entirely opaque flow control. They're the opposite of a goto statement: a comes-from statement if you will. Flow control could originate literally anywhere down the stack and that makes reasoning about what's happening very difficult. Depending on the language it can also have a super broad and ever-changing surface area.

There's nothing opaque about having an implicit potential return after every line as well as an implicit additional error result value. Think Go, but without the ceremony.

Re: Avoid exception throwing in performance-sensitive code

#82
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…

I must admit I use exceptions heavily for validation, e.g. checking input at API bounds. It makes the code fairly clean. I would imagine this is considered bad practice, but if there was no overhead this seems preferable over wrapping every call in some wrapper object. Any good links to further info on this?

so long as you’re not catching the exception and figuring out how to continue execution of the same function i think you have a good use case here. it’s no different than `assert`ing invariants at the top of a function, for example. if invariant is violated, the call should be aborted.

Re: Avoid exception throwing in performance-sensitive code

#83
post #43

Exceptions are starting to feel like a legacy programming paradigm to me. Rust & Go have, at least in a practical programming context, shown that errors-as-values has far less footguns and encourages better error handling practices than exceptions, which often are treated as an afterthought or end up being abused like in this post. Whenever I'm writing Python or Java I can't help but feel anxious about calling a func…

Rust do still has exceptions, they're just called "results". You can't really have values as exceptions unless you plug a lot of ad-hoc constructs into your language so that they eventually become similar to exceptions [1]:

> Add syntactic sugar for working with the Result type which models common exception handling constructs.

The whole error handling story with Rust can be summarized as "we have results but want to have exceptions".

[1] https://rust-lang.github.io/rfcs/0243-trait-based-exception-...

Re: Avoid exception throwing in performance-sensitive code

#84
post #43

Exceptions are starting to feel like a legacy programming paradigm to me. Rust & Go have, at least in a practical programming context, shown that errors-as-values has far less footguns and encourages better error handling practices than exceptions, which often are treated as an afterthought or end up being abused like in this post. Whenever I'm writing Python or Java I can't help but feel anxious about calling a func…

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.

Re: Avoid exception throwing in performance-sensitive code

#85
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…

One note: did you run the code w/ warmup and all, or just OSR (on stack replacement).

Re: Avoid exception throwing in performance-sensitive code

#86
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…

I must admit I use exceptions heavily for validation, e.g. checking input at API bounds. It makes the code fairly clean. I would imagine this is considered bad practice, but if there was no overhead this seems preferable over wrapping every call in some wrapper object. Any good links to further info on this?

If you involve |API| an external input, no one cares about the validation, that actually succeeds in virtually all cases. You should care only about the fast path - the rest are quite irrelevant (outside DoS attempts)

Re: Avoid exception throwing in performance-sensitive code

#87
post #22

Impossible to avoid in python.. exceptions are even how a simple for loop is implemented under the covers!

Is that still true in recent Python versions? Sounds like low-hanging fruit for perf optimisation.

Python 3.11 made the "try" part of exceptions zero-cost. The "except" part only has overhead if the exception is triggered.

Re: Avoid exception throwing in performance-sensitive code

#88
post #43

Exceptions are starting to feel like a legacy programming paradigm to me. Rust & Go have, at least in a practical programming context, shown that errors-as-values has far less footguns and encourages better error handling practices than exceptions, which often are treated as an afterthought or end up being abused like in this post. Whenever I'm writing Python or Java I can't help but feel anxious about calling a func…

At least for Go (haven't used Rust), I entirely disagree. After ~3 years of professional programming with the language, `if err != nil` is still constantly annoying me when writing code, but especially and most importantly, when reviewing code.

Not to mention, Go has proven conclusively to me that exceptions are exactly the right pattern for error propagation - the 99.9% pattern is "function returns error with message; callers add context; top-level caller aborts and logs + returns message to user, or sometimes retries". This is exactly how exceptions work out of the box, without the need to pollute all code between the error source and the top-level caller.

If anything, I'd like to see a language seeking to add smarter information to exception stack traces - not just the function + code line, but also some information about local variables might be doable, and would supplant the one occasional gap between Go-style hand-built context and Java/Python auto-generated exceptions.

Re: Avoid exception throwing in performance-sensitive code

#89
Here's another link about the problems with C++ exception that I find very insightful https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p25...

The major issue that stood out to me is that in a multi-threaded environment, exception unwinding is effectively single-threaded. This means that if you have C++ code that throws a lot of exceptions, you are going to see a lot of threads getting blocked by lock contention

Re: Avoid exception throwing in performance-sensitive code

#90
post #43

Exceptions are starting to feel like a legacy programming paradigm to me. Rust & Go have, at least in a practical programming context, shown that errors-as-values has far less footguns and encourages better error handling practices than exceptions, which often are treated as an afterthought or end up being abused like in this post. Whenever I'm writing Python or Java I can't help but feel anxious about calling a func…

Exceptions work well for 2 kinds of error handling: crash and log, and general retry and log.

The second one is more cumbersome with return values if the possible errors originate deep in the stack.

Beyond a simple retry, Exceptions are not specific enough for handling errors.

Post reply on HN