Live data from Hacker News

Avoid exception throwing in performance-sensitive code

lemire.me

231–240 of 243 posts

Re: Avoid exception throwing in performance-sensitive code

#231

Earlier quoted context omitted.

Maybe I misinterpreted you. I don't disagree that checked exceptions and errors are ~the same thing. > Go programmers, in 99.9% of cases, do manually what exceptions do automatically Our experience working with Go must be very different. Grepping for "err := " and looking at the first 10 results in my team's codebase. * 4 cases where the error is just returned * 1 case where the error is returned only if it matches a…

This actually argues my point, because it seems (ignoring the strange design) only the last case would really exist in business code in another language. (Obviously, without source code access the following is guesswork) The other cases might either not be required (since you'll get a stacktrace anyway and don't need to leave breadcrumbs) or be part of some general infrastructure, say interceptor, that logs interesti…

There is a lot of confirmation bias in this post. I will leave it at that.

Re: Avoid exception throwing in performance-sensitive code

#232

Earlier quoted context omitted.

I think a language's standard library sets a good pattern for how to write idiomatic code in that language. C++ throws on memory allocation error, but that's about it. Memory allocation errors are special in all languages. Because of lazy allocation and overcommit, unless you specifically set your environment to work otherwise, your program will probably just crash when it gets its first page fault that can't be hono…

> Memory allocation errors are special in all languages. Actually no, not in Java! You can catch java.lang.OutOfMemoryError just like any other exception. If the memory pressure is high though, it's possible that another OOM would be thrown from the code that handles it.

You can catch std::bad_alloc in C++, too. That's not my point. Especially because destructors free immediately (not wait for GC) I would expect C++ to handle this as a language much better than Java.

But when memory pressure is high you can get killed at any time. E.g. on Linux the OOM killer might decide that it's best for the system that your process dies, even if you've not done memory allocations or needed to page fault for hours.

IIRC OpenBSD doesn't overcommit memory, but in my experience its system stability is much worse when memory is low.

Re: Avoid exception throwing in performance-sensitive code

#233

Earlier quoted context omitted.

This actually argues my point, because it seems (ignoring the strange design) only the last case would really exist in business code in another language. (Obviously, without source code access the following is guesswork) The other cases might either not be required (since you'll get a stacktrace anyway and don't need to leave breadcrumbs) or be part of some general infrastructure, say interceptor, that logs interesti…

There is a lot of confirmation bias in this post. I will leave it at that.

Nevertheless, thanks for trying to back it up with data. I'll use your method and look at our code when time allows it, to see if I need to adjust my priors.

Re: Avoid exception throwing in performance-sensitive code

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

On the other hand the Rust syntax have gradually moved closer to exceptions, now with the "?" operator which automatically unpack the result or propagates the error value. This feels awfully close to exceptions, even if it in theory is "just a value".

Re: Avoid exception throwing in performance-sensitive code

#235
post #160

Earlier quoted context omitted.

You can build a separate exception for every possible raise site. But that is overly burdensome. Moreover, there is no guarantee that any (standard) library calls have an appropriately detailed taxonomy. You could, of course, wrap these library calls and catch exceptions so you can re-raise them yourself. But at that point you are losing the main advantage of exceptions over return values: the ability to separate the…

> You can build a separate exception for every possible raise site. Why would you want to do that? You don't do that with Result/Either. > To me, once I am building my own expansive taxonomy of exceptions, I am much happier using Optional, or Result/Either type return values. I may be missing something, because to me, this doesn't follow. Optional type is "result or nothing"; and with Result/Either type, you either u…

With result/either you are forced to handle the error very close to where it happend. With exceptions (in my understanding) the goal is to be able to handle errors much further up the stack. But in such cases you aren't sure where the exception originated, so you need to encode that in the exception to understand the error.

If you do very close exception handling, you lose what I consider to be 'the point of exceptions'. Hence I don't think that should be done.

The core of my argument is then that error handling beyond 'just retry' needs a lot of detail about the error. And I believe this detail is easier to encode if the error handling is close to the error. Since exception handling is meant to be further away from the error, it isn't as suited to this kind of error handling.

Re: Avoid exception throwing in performance-sensitive code

#236

Earlier quoted context omitted.

Return only ever moves up the stack one level. That makes it really easy to reason about. This can move up the stack an unlimited amount, and the handler has to be prepared to properly deal with the current state, no matter where it comes from.

This is no different than returning an error in go far down. You don’t know how far up it will be passed or handled.

You do. Errors have to be handled or passed up explicitly at each level. Errors are one level at a time, not 'n'.

Re: Avoid exception throwing in performance-sensitive code

#237
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 messag…

Absolutely agree with you on that front. Go's tedious error checking and manual rewrapping is pretty annoying and I'm sure there's a smarter way to do things waiting to catch on. That being said, I prefer that annoyance over the horrors of working in a codebase where exceptions are used for control flow, not checked at all, or just treated as an afterthought. In my experience, those programs tend to be fragile, often crash with little context, or just silently continue after a failure. At least Go forces you to deal with it.

Re: Avoid exception throwing in performance-sensitive code

#238
post #170

Earlier quoted context omitted.

>it looks as if 2/3 of a Go program is pure error handling and no business logic. This is exactly why it's good. It forces developers to think about things outside the happy path business logic. And it does this at the point where they know best what such an error could mean. Proponents of exceptions let their users catch the exceptions they overlooked. If you ask me Go is not forcing this enough, the ML style Result…

> This is exactly why it's good. How did we manage to get this far before people ~~went insane~~ decided that this is somehow favourable?

After working in an SRE-type role on a codebase full of unchecked exceptions, or exceptions that are caught at the wrong levels because programmers just want their code to work - forcing the explicit handling of errors is favourable because it requires developers to think about what they really want to happen when something goes wrong at this point in the code. Whereas without it, often they will simply catch the exception and continue on silently, or re-raise it without proper context.

Conversely, sometimes there are really simple cases that are totally ignored by programmers because they forget that an exception might be thrown. The worst offender in my experience is in Python where people assume the existence of dictionary keys and get KeyError exceptions, or NoneType exceptions. Without type hints, there's no mechanism to warn you as you write the code that these things could occur. So programmers don't plan for it. If there are explicit errors, the programmer is forced to consider the case that the key they want doesn't exist, or that this variable isn't actually the type they expect (static typing helps here too).

In general, I think this prevents footguns when you are working on large programs. It's worth the verbosity.

Re: Avoid exception throwing in performance-sensitive code

#239
post #92
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…

Has it shown this? Are there solid metrics or is it simply because they're popular and it's not the idiomatic way to do things? My understanding is they still have panics anyhow.

I should have caveated that it's purely subjective. In my experience, developers write much more reliable and understandable code when they handle errors as values rather than as exceptions.

Re: Avoid exception throwing in performance-sensitive code

#240
post #234
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…

On the other hand the Rust syntax have gradually moved closer to exceptions, now with the "?" operator which automatically unpack the result or propagates the error value. This feels awfully close to exceptions, even if it in theory is "just a value".

I think the main difference is that it forces the acknowledgement of the error at the point of the function call, which is not the case with exceptions.
Post reply on HN