Live data from Hacker News

Avoid exception throwing in performance-sensitive code

lemire.me

221–230 of 243 posts

Re: Avoid exception throwing in performance-sensitive code

#221
post #128

Earlier quoted context omitted.

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.

It unwinds the call stack until a catch. It is the same "problem" as not knowing where a return will return to.

No, it is not the same problem. You need to trace every function, and every function calling those functions, and every function calling those functions, all the way to catch.

You can't "just" search for function name, you have to rely on code analysis tools.

Making code more opaque coz you can get thru the mess of it via tooling is terrible direction

Re: Avoid exception throwing in performance-sensitive code

#222
post #208

Earlier quoted context omitted.

C++ isn't an industry language?!?

There're no checked exceptions in C++. noexcept does not do anything related to type system, it just terminates an application if an exception has been thrown.

CFront until C++11, and Herb's paper for value type exceptions...

Re: Avoid exception throwing in performance-sensitive code

#223
I don't understand why this blogpost is getting so many upvotes.

Anyhow! I use exceptions and page faults to optimize my loops. There's no need to check a loop's condition every iteration when you can abuse an intentional error to do it for you. Also works great using page faults!

Re: Avoid exception throwing in performance-sensitive code

#224

Earlier quoted context omitted.

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

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.

Re: Avoid exception throwing in performance-sensitive code

#225

Earlier quoted context omitted.

I'm talking about unchecked exceptions. It's not about what is possible it's about what patterns a language encourages. It feels like we've lost the thread of discussion. - You say there is no difference between unchecked exceptions and Go's errors - I say yes there is since Go forces users to handle errors explicitly - You say that's not technically true in all cases. OK. Yes. I should have said "nudges users" inste…

> You say there is no difference between unchecked exceptions and Go's errors Where do I say that? I say that Go programmers, in 99.9% of cases, do manually what exceptions do automatically. In terms of cumbersome, error values are the equivalent of checked exceptions. The equivalent of runtime exceptions are panics.

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 certain type (otherwise logged)
  * 1 case where the error is logged as a warning.
  * 1 case where the error is logged, some metric is incremented, and then execution continues as usual. (a fail-open authentication check)
  * 1 case where the error is returned as different error type.
  * 1 case where the error is returned, but only after accessing the result (this is a strange design / antipattern), and annotating it with a human-readable explanation.
  * 1 case where the error is treated as a boolean condition, and is not returned. (the error condition is "does not exist").
So in this sample it matches the "automatic behavior" in only about half the cases. In other cases, substituting the existing behavior with exception's automatic behavior would cause severe bugs.

Re: Avoid exception throwing in performance-sensitive code

#226

Earlier quoted context omitted.

> You say there is no difference between unchecked exceptions and Go's errors Where do I say that? I say that Go programmers, in 99.9% of cases, do manually what exceptions do automatically. In terms of cumbersome, error values are the equivalent of checked exceptions. The equivalent of runtime exceptions are panics.

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 interesting things on boundaries. At least that's my day to day experience comparing Go and Java.

Re: Avoid exception throwing in performance-sensitive code

#227
post #170
post #159

Earlier quoted context omitted.

Absolutely. Even after "compressing" my code as much as possible, it looks as if 2/3 of a Go program is pure error handling and no business logic. I just don't understand this militant objection toward exceptions now. Even back in the days of slower virtual machines and crappier hardware, we were fine , and now it's code red! Get rid of exceptions! Performance! This is in an era of tech where everyone is building BAD…

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

Re: Avoid exception throwing in performance-sensitive code

#228

Definitely depends on the language. OCaml exceptions are quite performant, for example, and get used in a lot of ways that you probably wouldn't want to use them in other languages.

Yes, raising an exn in OCaml is close to jumping to an address stored in a register. https://stackoverflow.com/a/8567429

As a result, raising and catching exns in OCaml is cheap. List.fold_until in Base, for example, is implemented with exceptions: https://github.com/janestreet/base/blob/ae169dc8097b3da8e99d... (With_return is internally implemented by raising an exception in a try-with.)

Implementations of functional programming languages often have powerful, yet fast!, non-local control-flow primitives. GHC recently sprouted delimited continuations (https://ghc.gitlab.haskell.org/ghc/doc/users_guide/9.6.1-not...), for example, and Lisps have had that for much longer. It's easy to program in an imperative language for a long time and think that straight-line control flow is the end-all, be-all for performance—but it doesn't have to be the case.

Re: Avoid exception throwing in performance-sensitive code

#229
post #128

Earlier quoted context omitted.

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.

You’re missing the point of exceptions. When you throw an exception, you’re not supposed to care where it lands. That’s the caller’s responsibility.

“Who will catch this” is supposed to be opaque. It’s like wondering who will call this function.

If you want to goto some specific point in the code, just call it.

Re: Avoid exception throwing in performance-sensitive code

#230

Earlier quoted context omitted.

It unwinds the call stack until a catch. It is the same "problem" as not knowing where a return will return to.

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.
Post reply on HN