Live data from Hacker News

Avoid exception throwing in performance-sensitive code

lemire.me

211–220 of 243 posts

Re: Avoid exception throwing in performance-sensitive code

#211
post #208

Earlier quoted context omitted.

Those are not industry languages and Java was known to borrow only well developed and widely adopted features. For example it took like 20 years to add lambdas which were in lisp 60 years ago. Checked exceptions are a sore exception to this rule.

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.

Re: Avoid exception throwing in performance-sensitive code

#212
post #205
post #149

Earlier quoted context omitted.

I long wished there was C# Intellisense that showed what kind of exceptions I may receive when calling particular function. At least from code it can infer from: - .NET library has documentation comments, with tags - It could look at my code and see what exceptions get thrown. - It could be clever enough to know that new might throw OutOfMemoryException - Clever enough to know checked arithmetic might throw OverflowE…

What you are asking for is checked exceptions where the caller gets notified by the compiler that the function you call might throw one or more exceptions. However, it is worth taking it a step further and focus on "why the error occurred" instead of "an error has occurred". An example of this is Code Contracts. Like Intellisense, live code analysis with contracts would tell you "the method you call will throw with t…

Well, code contracts are unfortunately dead, not available in .NET Core.

C# Anders Hejlsberg, C# designer has a word on checked exceptions for which I agree with him that we should somehow address it more efficiently: https://www.artima.com/articles/the-trouble-with-checked-exc...

Looks like what I'd like in the meantime is soft-checked-exceptions. Well, just for documentation purposes. And I'll leave the code for myself. I just want to take into consideration various failure modes and now I can just do generic error handling or waste too much time. Yes, what you are saying, live code analysis would be good enough not to screw up C# language itself with bad design decisions.

Re: Avoid exception throwing in performance-sensitive code

#213

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?

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 honored.

Open a file? fstream sets .is_open() (or its operator bool, so just "if (!f)")

Write fails? Sets .fail()

POSIX stuff usually return an error code, and set errno.

Modern C++ has std::optional.

But there's of course another answer to this, and that is "C++ has zero cost abstractions", meaning for example if you don't check for nullptr, then neither will the language. There's no NullPointerException because C++ just says that this is Undefined Behavior.

Oh, here's one: If you use dynamic_cast to try to downcast into the wrong type, that'll throw an exception. But first of all: don't downcast, and second of all: This is not an "unexpected input to function". This is a complete programming error and it's probably best to terminate. I.e. this is something Go style would panic about, not return an error.

Do you have more specific examples about unexpected input to a function that you would want to return an error for?

Ugh. Actually std::stoi() violates this pattern. If std::optional existed in C++11 it would probably have been used here.

Re: Avoid exception throwing in performance-sensitive code

#214

Earlier quoted context omitted.

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…

Entire books, I'm sure, have been written about the pro and cons of exceptions for error handling.

Yes, I called it "idiomatic C++" before, but reasonable people disagree about the best option.

Smarter people than me have written good things in the E section of the C++ Core Guidelines. The people involved have overlap with the C++ standards committee:

http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#...

At least if you use exceptions for errors C++ doesn't need "finally", because it has working RAII, unlike Java.

Re: Avoid exception throwing in performance-sensitive code

#215
post #156

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.

Rust uses Result. Checked exceptions are Java's analogue of Result.

I disagree. Exceptions are a fundamentally different control flow. Exceptions are exceptions. Return values are not.

I would not call std::optional in C++ any form of checked exception, and the difference isn't that std::optional doesn't carry value-missing metadata.

Re: Avoid exception throwing in performance-sensitive code

#216
post #84

Earlier quoted context omitted.

> where library code can suddenly abort and the author shrugs and says "shoulda read the docs". In see no difference. Except for the fact that you don't have the stacktrace (in Go), and unroll the Stack manually. In any case, there'll be a generic catch (whatever you call it) on the top level of your daemon to recover from the failed request and handle the next.

The difference is that the error states are explicit rather than implicit. The function's signature tells you what the possible errors you'll need to handle are, so you don't get caught off guard at runtime. As for stack traces: checked exceptions are semantically almost identical to error-as-value but they do give you a stack trace. They give you all the static guarantees of error-as-value plus the benefit of being…

> checked exceptions are semantically almost identical to error-as-value but they do give you a stack trace

I completely agree with you on that one. The only thing I'd want to add is that aside from example code, usually you don't care a lot about what specific errors might pop up, unless you're at the top level of your program. This might be the request handler, or some UI loop. On the other hand, where you care about errors, you usually don't care about results or their types.

I've been in the industry long enough that I vividly remember the catch-and-wrap orgies in Javaland of 2003. A lot of it was caused by the inferior type system of Java, which hinders composability (such as when a layer is moved to another node and suddendly you have to deal with remoting exceptions). But it also goes to show that knowing a specific class of error is often overrated in application code, and should be, well, the exception.

Re: Avoid exception throwing in performance-sensitive code

#217
post #66

Earlier quoted context omitted.

Java has them now but it didn't at the time (and even now they're kind of bodged in IIRC).

I don't think Java has support for CL condition system-style restarts. You're maybe talking about exceptions that simply don't populate the stack trace? To clarify a bit, in CL, when throwing an exception, you can optionally register one or more "restarts", which are essentially lambdas of 0 or more parameters. When the exception is thrown, the stack is walked to find the appropriate handler, but it is not unwound. W…

Pretty sure GP was talking about first-class functions not condition-system &c.

Re: Avoid exception throwing in performance-sensitive code

#218

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…

In the C# stdlib there is at least currently the Task and ValueTask pair, where the latter is a struct optimized for 'failure is rare and success is synchronous' that degrades smoothly to the former, which can represent asynchronous computation and lets you recover failure exceptions w/stack without having to ever actually throw. I do wish the async part was decoupled from it, but it's nice that all the error informa…

While correct in terms of convenience, it still wraps an exception with all associated costs. But yet again, you can hand-roll custom `Result` even today and implement something like `.Wrap(Func func)` that would produce `Result` to interoperate.

Anyway, if the callee throws an exception, it will be just as costly as any other even if you can examine the `Value/Task` for `.IsFaulted` and `.Exception`.

Possibly counterintuitively, if thrown, it will also dwarf the overhead of allocating state machine object and executing `MoveNext()` decoration. Hence even in async there is value to be had in not using exceptions in performance-sensitive scenarios.

Re: Avoid exception throwing in performance-sensitive code

#219

Earlier quoted context omitted.

IMHO, quite often when you're tempted to handle an error, you're either wrong to do so, or in some kind of infrastructure glue code. A request handler, a task executor, a strategy chain, a retry loop, you name it. And this code needs to deal with both classes of errors anyway to be bugfree.

From those examples, I think only request and task should deal with panics. Things that start threads or processes. Other points of "catch all errors" don't need that. And then there are a lot of places where you do handle errors, if they are conceptually a Result. I know you can just catch SpecificError, but the ergonomics are just horrible in terms of control flow.

I don't think threading is relevant to this.

> there are a lot of places where you do handle errors, if they are conceptually a Result

Yet, what's conceptually a result lies in the eye of the beholder, and should not be dictated by an API designer IMHO. Rust's ? is a step in the right direction, but I'd argue since you care about specific errors in maybe 0.1% of invocations tops (in production code), and that's a stretch, the ? should actually work the other way round. And if the mechanism does not provide a way to select specific errors (such as a proper catch clause) the errors it exposes as a result should include runtime errors as well.

Re: Avoid exception throwing in performance-sensitive code

#220

Earlier quoted context omitted.

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…

Entire books, I'm sure, have been written about the pro and cons of exceptions for error handling. Yes, I called it "idiomatic C++" before, but reasonable people disagree about the best option. Smarter people than me have written good things in the E section of the C++ Core Guidelines. The people involved have overlap with the C++ standards committee: http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#... At…

In modern Java, and by modern I mean 8 and newer, you no longer need "finally", there's "try with resources" instead that would close everything upon leaving the try block:

    try(FileInputStream in=new FileInputStream(file)){
        // do something with the file data
    }catch(IOException x){
        x.printStackTrace();
    }
It's been a very long time since I last wrote "something.close()".
Post reply on HN