Live data from Hacker News

Avoid exception throwing in performance-sensitive code

lemire.me

41–50 of 243 posts

Re: Avoid exception throwing in performance-sensitive code

#41

Earlier quoted context omitted.

Seems like a language design flaw that this is slow. Imo Rust got this right by making "exceptions" nothing special, just a data type holding an error which can be processed just as fast as anything else.

Exceptions are not the Error/Result type in Rust, they are panics. Which can be very expensive. But thankfully rust does them right and only uses them for unrecoverable errors.

You're right, what Rust gets right is standardized errors that aren't exceptions. In other languages you pretty much just return {success: false, message: ""} or whatever million combinations of this idea people sprinkled in the code.

Having a single type handle this with a bunch of utility functions associated is great.

Re: Avoid exception throwing in performance-sensitive code

#42

TIL that it's even possible to use exceptions instead of bog standard if statements. Would love to know why people would do this, though. Surely everyone masters if-else ssatements well before they even learn what a try-catch statement is!?

Using exceptions as control flow is a pattern I saw a lot at AWS in Java code. It boiled down to it was simpler to abuse exceptions. You could instead return objects, but the code simply ended up being more to write. At some point I tried to write things the 'proper' way by returning a Result object with the possible states, but it ended up being more complex than just throwing exceptions.

It’s because Java supports nonlocal returns and pattern matching, but only when you use exceptions. Returning POJOs to report problems makes all the intervening code harder to read because the happy path is no longer separated.

Re: Avoid exception throwing in performance-sensitive code

#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 function and having absolutely no idea if or what exceptions it might throw, and then having to resort to digging through documentation or class hierarchies to figure it out.

Re: Avoid exception throwing in performance-sensitive code

#44
post #35

Earlier quoted context omitted.

C++ exceptions and by extension Rust panics and C# exceptions (with caveats) involve stack unwinding as well as gathering of corresponding details and producing an exception object (C#). It is very expensive and using it as a normal condition in general is not the best idea. It is by definition cannot be optimized in a way that gets both good performance and keeps all existing side effects. That's why Rust's Result i…

I don't know how it is now, but back in the day C++ exceptions were so messy and non-performant that Google forbid their use in company C++ code. And they employed at least one member of the standards committee!

Looks to still be the case:

https://google.github.io/styleguide/cppguide.html#Exceptions

One could argue this is something of a technical debt issue, as the rationale notes:

> "Given that Google's existing code is not exception-tolerant, the costs of using exceptions are somewhat greater than the costs in a new project. The conversion process would be slow and error-prone. We don't believe that the available alternatives to exceptions, such as error codes and assertions, introduce a significant burden."

> "Our advice against using exceptions is not predicated on philosophical or moral grounds, but practical ones. Because we'd like to use our open-source projects at Google and it's difficult to do so if those projects use exceptions, we need to advise against exceptions in Google open-source projects as well. Things would probably be different if we had to do it all over again from scratch."

Re: Avoid exception throwing in performance-sensitive code

#45
post #35

Earlier quoted context omitted.

C++ exceptions and by extension Rust panics and C# exceptions (with caveats) involve stack unwinding as well as gathering of corresponding details and producing an exception object (C#). It is very expensive and using it as a normal condition in general is not the best idea. It is by definition cannot be optimized in a way that gets both good performance and keeps all existing side effects. That's why Rust's Result i…

I don't know how it is now, but back in the day C++ exceptions were so messy and non-performant that Google forbid their use in company C++ code. And they employed at least one member of the standards committee!

  "On their face, the benefits of using exceptions outweigh the costs, especially 
  in new projects. However, for existing code, the introduction of exceptions has 
  implications on all dependent code. If exceptions can be propagated beyond a
  new project, it also becomes problematic to integrate the new project into
  existing exception-free code. Because most existing C++ code at Google is not 
  prepared to deal with exceptions, it is comparatively difficult to adopt new 
  code that generates exceptions." (https://google.github.io/styleguide/cppguide.html#Exceptions)
So, basically, Google forbids exceptions for historical reasons, not because of performance.

But, sadly, countless companies parroted this section of Google's style guide for all the wrong reasons (mostly just cargo culting Google) leading to unfortunate fragmentation of error handling in the C++ library ecosystem.

Re: Avoid exception throwing in performance-sensitive code

#46
post #29

Earlier quoted context omitted.

Seems like a language design flaw that this is slow. Imo Rust got this right by making "exceptions" nothing special, just a data type holding an error which can be processed just as fast as anything else.

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

IIRC, that's why Go errors don't come with stack traces by default, performance.

I'll admit that this has enraged me on a few occasions when all I have to work with is a logged error message of

   strconv.ParseInt: parsing "": invalid syntax
With no clues as to where the hell the error actually happened, so I have to start grepping the app's code, then the code of its dependencies, then the code of the dependencies' dependencies.

Re: Avoid exception throwing in performance-sensitive code

#48
For JS devs, I’ve found it’s actually best to isolate your exception handling from exceptional logic. As in, this will perform worse called in a hot loop:

  function fallible(a) {
    try {
      return anything(a)
    } catch {
      const b = somethingElse(a)

      return anotherThing(b)
    }
  }
… than if your somethingElse case handles anotherThing, or if you do more work in the try block. In some cases exception throwing outperforms if conditions as long as both the try and catch blocks only do one thing each.

Re: Avoid exception throwing in performance-sensitive code

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

Re: Avoid exception throwing in performance-sensitive code

#50
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 check for actual exceptional cases, you have next to no overhead. The overhead comes from creating the exception environment and going up the stack in unusual ways. For validation where most data is correct, this should have next to no impact.
Post reply on HN