Live data from Hacker News

Avoid exception throwing in performance-sensitive code

lemire.me

121–130 of 243 posts

Re: Avoid exception throwing in performance-sensitive code

#121

Earlier quoted context omitted.

You seem to believe options B to D are not available to programmers in languages with exceptions. The real value comes from making option E much more unlikely: ignoring both the result and error value altogether, because you relied on the side effect of the function you called.

You might like how Rust does error handling. Rather than a function returning a triple of (val, error) where the error can be ignored, functions return Result . If you want to get the T, you must write code that handles both possibilities. If your function instead wants the T and propagate the E upwards if it exists, you can do that with one character - “?”

I indeed like Rust's approach a lot more than Go's. What I like less still is that it gives the impression that it's even possible to define functions that cannot fail. This is not true. One just has to look at how runtimes deal with stack overflow errors to see how the good old Java RuntimeException creeps in in various forms (e.g. panics) because checked exceptions and it's recent incarnation as error values are a leaky abstraction.

Re: Avoid exception throwing in performance-sensitive code

#122
The author mentions Go, but Go has "exceptions" too in the form of panics. I tested the speed of throwing panics, and if the error type evaluation is involved, the panics don't lag behind returning errors one bit. I even created an experimental library to support this in a playground project: https://github.com/apitalist/lang

Re: Avoid exception throwing in performance-sensitive code

#123
post #36
post #29

Earlier quoted context omitted.

> Seems like a language design flaw that this is slow I think stack traces take up much of the time, including converting it [1]. Without them it could probably be a lot faster. Also see hashmash's post. But other than that, there is the logic issue, not using exceptions for normal flow control makes sense at least to me too independent of any performance questions. [1] For a Java example: https://ionutbalosin.com/20…

This is another reason why Common Lisp style condition system (where exception handlers can execute without unwinding the stack) just seems to work better. If you need the stack, get the stack, if you don't then just use handler-case. I really don't see the downside for any language that has anonymous function literals.

CL condition system is based on error handlers, which is the 3rd paradigm aside from returning error values and exceptions. Unfortunately, it didn't really permeate the Unix based languages (C, C++, Java), because Unix had completely kneecapped implementation of error handlers in the OS (lack of user defined signals and their hierarchy). Error handlers are so much underrated that even books like Code Complete do not mention them.

Each of the three paradigms has pros and cons in terms of code simplicity and runtime cost (in normal/error path), I don't think there is a clear winner.

Re: Avoid exception throwing in performance-sensitive code

#124
post #96

Earlier quoted context omitted.

99.99% (maybe even more) of game engines is not performance critical code though. I guess the reason was a different one: for exceptions to work you need a sane memory model. It's very hard to write exception safe code in C++. A garbage collector is very helpful to accomplish that, and _this_ is the thing that's problematic, because it interferes with the 0.01% performance critical inner loops.

> It's very hard to write exception safe code in C++. How? As long as RAII is used it's basically for free.

But there are a bunch of codes which are yet to be verified as exception-safe. And in the gaming industry it's often third party code that you cannot even inspect.

Re: Avoid exception throwing in performance-sensitive code

#125

Earlier quoted context omitted.

I think most serious C++ shops are probably compiling with -fno-exceptions.

That is entirely false. You can barely even use half the language without exceptions.

I don't really know how you'd falsify the claim (it's not particularly falsifiable), but I'm open to being wrong... That being said, only using 50% of a language like C++ might be considered a feature and not a bug. ;)

Re: Avoid exception throwing in performance-sensitive code

#126
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 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

They don't really. Because they force you to handle errors even in code that couldn't care less about errors because that's the responsibility of a higher level up the stack. And worse, they assume that an exception is a valid reason to just stop program execution altogether (when it rarely is).

See Erlang for how you should handle exceptions (you have a supervision tree with various restart strategies).

Re: Avoid exception throwing in performance-sensitive code

#128

Earlier quoted context omitted.

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.

This is not correct, a “comes-from” statement would still be the same behavior as a goto except it’s defined at the label and there is no “goto” at the departure line. Exceptions are just “goto whatever catch is in the call stack”. It’s still completely obvious when you see a throw statement that it can throw, and static analysis can tell you exactly what can be thrown by each function.

And it is still opaque where it goes to the programmer when they see it in code. The fact you can use tools to find where it might land (yeah, no shit, you can do same for goto...) is just a mitigation to the problem.

Re: Avoid exception throwing in performance-sensitive code

#129
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?

Think that's probably the best use case actually - API bounds are often "just check a bunch of stuff, from AA thru data validity to whether connection finished cleanly" so just putting catch over whole request handling is easy to reason about.
Post reply on HN