Live data from Hacker News

Avoid exception throwing in performance-sensitive code

lemire.me

171–180 of 243 posts

Re: Avoid exception throwing in performance-sensitive code

#171

Earlier quoted context omitted.

Errors in rust are not exceptions, they're data contained within an `Either` monad (Result) Additionally, on top of the linked RFC being nearly 9 years old it doesn't at all indicate "we want to have exceptions". The ? operator allows propogating the errors if they can't be immediately handled (similar to monadic `do` notation, or early returns)

Just because Rust people are in denial about it doesn't make them not exceptions. The Either/Result monad is isomorphic to checked exceptions, with any differences being pretty much just syntax.

It makes generics and higher-order functions much more elegant. Any function of `(a->t)->t`(or many other similar signatures) will automatically be able to return the correct error type if t is a Result.

Compare this to checked exceptions, where (even in an ideal world) you'd need a separate type parameter for the error type, plus a bunch of extra language features and syntax to make it work. And then what happens if you want to use the same function with _no_ error type?

For a concrete example, try using Java's `stream().map()` with checked exceptions.

Of course there are implementations of checked exceptions which are much closer to Result than Java's implementation, and in those cases I would agree with you.

Re: Avoid exception throwing in performance-sensitive code

#172
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".

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 still be thrown, but you're not supposed to deal with it in any way in most code).

2. You can declare method as `throws Exception1, Exception2`. Compiler will ensure that only subclasses of those exceptions are thrown from this method.

3. You can omit any declaration. In this case compiler will compute list of possible exceptions implicitly (it's a union of all exceptions thrown by all called methods).

So basically it'll allow to: document list of thrown exceptions and it'll allow to statically check that other exceptions are not thrown, so this documentation is compiler-checked.

Of course this idea needs battle testing, but I think that I'd like it. You can either opt-in and write code documenting all thrown exceptions (which is good for libraries) or you can opt-out and write simple code without bothering with exceptions (which is good for applications).

Also there should be proper support for generic exceptions, so I can write Function and E would be of type containing union of all thrown exceptions. That's required for example for moving exception signatures from lambdas in functional collections.

Re: Avoid exception throwing in performance-sensitive code

#173

Earlier quoted context omitted.

> it gives the impression that it's even possible to define functions that cannot fail Do you mean that e.g. an out-of-bounds error will panic? If that's the case, you can always access arrays/slices with some checked access, that will return a Result/Option and cannot panic. But it would be a PITA if you couldn't skip that.

I mean stack overflows or out of memory errors. It might fail one request, but no reason to fail all others.

That's a very specific case, that could be handled non-trivially.

Usually your HTTP framework will already have this implemented, i.e. a panic in a request handler will be "caught", converted to some 500 response, and should not affect other requests.

Re: Avoid exception throwing in performance-sensitive code

#174

Earlier quoted context omitted.

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. ;)

More anecdata my shop didn't allow exceptions in production code until very recently. I've written c++ with no exceptions for a quarter century. Now that I'm allowed to add them, I don't want to. I don't like the invisible control flow. I like how rust does it. Mostly my shop still ignores exceptions unless a dependency uses them.

What half of the language am I missing?

Re: Avoid exception throwing in performance-sensitive code

#175
post #93

This was a fairly common position when I was programming C++ over a decade ago. Performance critical code like game engines, etc used to avoid exceptions like the plague. Not entirely surprised to find that’s still the case.

With the 32-bit x86 ABI, exceptions hurt any time your code had the possibility of throwing one. The 64-bit ABI fixed that, and is REALLY slow when an exception shows up, but does not cost anything in the happy path.

Re: Avoid exception throwing in performance-sensitive code

#176
post #152

Earlier quoted context omitted.

It also depends on the language. For example, Python very much operates under the "ask for forgiveness, not permission" mantra, and I even see this used for dict lookups. The number of times I encounter code like this: try: my_dict[key] catch KeyException: pass rather than if key in my_dict: my_dict[key] is astounding. I don't know what the performance difference is in Python though.

What about thing = my_dict.get(key) if thing is None: ...

yes, my_dict.get() is my preferred solution too, if I can come up with a sensible default value or action. Otherwise, I do my_dict[key] without try/except. But I'm not sure if that's just a style preference or if there's a large performance difference in Python.

Re: Avoid exception throwing in performance-sensitive code

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

It does sound abusive since validations are expected to fail and so should not require an alternative way to return their outcome.

Re: Avoid exception throwing in performance-sensitive code

#178
post #152

This post is poorly named. What it's saying is to avoid throwing exceptions for normal flow control, and just use them for exceptional cases (file not found, etc). Performance-sensitive code or not, exceptions for exceptional situations are not going to hinder the app's performance until the exceptional situation becomes common (unless your language does lots of exception setup work on the happy path - which most hav…

It also depends on the language. For example, Python very much operates under the "ask for forgiveness, not permission" mantra, and I even see this used for dict lookups. The number of times I encounter code like this: try: my_dict[key] catch KeyException: pass rather than if key in my_dict: my_dict[key] is astounding. I don't know what the performance difference is in Python though.

The later should require two lookups unless it is optimized away.

Is there an easy way to get bytecode for Python snippets?

Re: Avoid exception throwing in performance-sensitive code

#179

Earlier quoted context omitted.

Java is the... uhm... exception here. That's not how idiomatic C++ is. Nor Rust. Nor Go. One of Java's (incl standard library) main design flaws is overuse of exceptions. It should not be emulated. It's too late to fix Java, but that doesn't make it a good idea.

So what do you do in C++ if the input to your function is not what you expect?

Return an error or fatally exit the program, depending.

Re: Avoid exception throwing in performance-sensitive code

#180

Earlier quoted context omitted.

So what do you do in C++ if the input to your function is not what you expect?

Return an error or fatally exit the program, depending.

If you return an error, it needs to be checked for in every place where this function is called. Yes, I know C libraries and OS APIs do this often, but that's C, it's the only thing it can do. This just invites human error. Besides, it's often desirable to handle multiple different error conditions (arising from different steps as you process the input data) in one place, which is complicated with this approach. Java-like exception handling makes it easy to handle all errors in a single place and be sure none go unnoticed. This is especially useful when you're accepting external input (a file, a network packet/stream, an HTTP request, etc).

If you exit the program on error, this does work in some cases like command-line utilities, but your users would not be happy if your GUI app crashes when you open a malformed file.

Post reply on HN