16 ms·
Avoid exception throwing in performance-sensitive code
- version_five 4y agoI'm completely ignorant of the subject, but most surprising to me in his example was that the compiler didn't optimize away the inefficiency. Is there something about exception handling that makes it not get taken into account during optimization?
- cma 4y agoWithout profile guided optimization you normally assume it will want a slow path. For one, handling it far away rather than nearby inline, which would hurt cache efficiency (either wasted within a cache line or extra wasted prefetching) if there weren't exceptions being thrown.
- vgatherps 4y agoC++ exceptions have a lot of machinery behind the scenes, and I don’t think anybody has ever really put the effort in to optimize pathological edge cases like this.
- int_19h 4y agoA lot of time and effort went into optimizing the most common case (no exceptions - ideally this should be no-cost) at the expense of everything else. It's very much by design.
- vgatherps 4y agoYes, 100%! This is exactly the machinery the makes it hard for a compiler to elide the exception. I don’t think there’s anything in the standard that prevents the compiler from optimizing away said exception completely, but neither gcc or clang do so even in extremely trivial cases where the exception is identical to an if statement: https://godbolt.org/z/8Y81bzo5s https://godbolt.org/z/8Y81bzo5s
- jamesfinlayson 4y agoI'm no C++ expert but I think it must be hard for the compiler to figure out - the noexcept keyword exists in C++ to denote a method that doesn't throw exceptions (so the compiler knows it doesn't need to add default exception handling code). Given that this is a manual thing up to the programmer it mustn't be straight forward for the compiler to infer.
- beached_whale 4y agonoexcept actually forces it, if it doesn’t know it must essentially wrap the function body in a try { …body… } catch(…) { terminate( ); }. So the compiler is doing the same amount of work inside the function. Outside it can assume that no exception will escape that function, yes. If it knows, it doesn’t need to.
- pclmulqdq 4y agoExceptions in C++ have a ton of slow machinery, so available optimization is limited, and they are assumed to be... exceptional... so they are not generally speed-optimized. If you are expecting an occasional exception in a C++ program, std::optional with error checking will make you a lot happier.
- shadowgovt 4y agoOn top of everything else, the behavior of exceptions when mixed with setjmp and longjmp is undefined, which can be a real problem if you're using any libraries that you haven't exhaustively analyzed to confirm that they don't use that feature. If memory serves, this includes things like the Lua interpreter (ETA: this used to be true. ca 2008, the Lua interpreter was changed so that it can conditionally compile to implement its try/catch via setjmp / longjmp or via C++ exceptions). I generally consider exceptions in C++ harmful and avoid them if possible. It is not, unfortunately, always possible, as exceptions are the only way the language defines for constructors to fail.
- deleted 4y ago[deleted]
- neonsunset 4y agoC++ 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<T, E> is vastly superior because it out of box pushes the users to very efficient and idiomatic error handling mechanism which is based on its enum types that enjoy a lot of compiler optimizations. You can also achieve fairly good results with struct-based custom Result<T, E> implementations in C# but until the language gets the support of proper discriminated unions, it will always be inferior. Thankfully, in C# and, I assume, in other exception-based languages the compiler is smart enough to recognize exceptions as cold paths and correctly reorder emitted code to minimize their impact when you do not throw them. But traversing try-catch blocks still tends to pessimize the codegen significantly hence heavy reliance of C# on various throw helpers to keep hot paths clean.
- User23 4y agoI 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!
- photochemsyn 4y agoLooks to still be the case: https://google.github.io/styleguide/cppguide.html#Exceptions 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."
- tsimionescu 4y agoExceptions in all modern C++ compilers are implemented in a way that prioritizes the performance of cases where an exception is NOT thrown at the cost of performance when an exception is thrown. Note that this means C++ code should be slightly faster than equivalent C/Go/Rust-style code that has to do an if/else after every function call that can fail to check if it did. Once this decision was made, investing time in optimizing programs that use exceptions for regular control flow became very very low in the priority list of all C++ compilers. This would include recognizing cases where an exception could be replaced with a single if/else, and optimizations for the unhappy path in general.
- mcqueenjordan 4y agoBranch prediction.
- pclmulqdq 4y agoExceptions are great for exceptional conditions in performance-sensitive code. They provide a mechanism to move your error-handling code far out of the hot path. If you are expecting an occasional exception, they are terrible, and the C way of returning an error code is the way to go. In most cases, when you don't control what you expect, exceptions are not great. In a constrained embedded system or a trading system, they can be amazing.
- bogwog 4y agoWhy would error-handling code impact performance? Besides, exceptions in C++ are known to have negative impacts on overall performance even if you don't use them. (see: https://preshing.com/20110807/the-cost-of-enabling-exception-handling/ https://preshing.com/20110807/the-cost-of-enabling-exception...)
- int_19h 4y agoThis blog post is specifically talking about 32-bit x86 C++ ABI, which was notoriously not zero-cost wrt exceptions even on success-only code paths. Lessons learned from that went into the Itanium C++ exceptions ABI based on static unwind maps, which has been adopted by basically every other architecture except for Windows, which has its own take (that is still zero-cost).
- vlovich123 4y agoHuh? It’s for skylake which works imply x64 no? I doubt Daniel Lenore is running 32 but code given his background of focusing on applying AVX everywhere which requires x64. X64 uses itanium exception handling.
- Kranar 4y agoOP was ambiguous, he means that the article "The Cost of Enabling Exception Handling" that was linked only applies to Windows x86, not to Windows AMD64 or the Itanium ABI. The Itanium ABI and 64-bit Windows have near-zero cost when exceptions aren't thrown.
- hashmash 4y agoDifferent 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 runs about 10 times slower. If I throw a singleton exception instance, then the performance is identical. The reason why the performance is identical is because HotSpot inlined the code and converted the immediate throw-catch into a simple goto. It wasn't smart enough to see that the stack trace wasn't needed, nor was it smart enough to see that allocating new instances wasn't needed either. I had to make those transformations manually.
- nhoughto 4y agoGreat details! Why only half the time though? What is the behavior the rest of the time?
- hashmash 4y agoI wanted to make sure all code paths were executed, and so I filled the array of ints with 50% negative values.
- User23 4y agoThanks for this short and fine example of Java optimization. I still have a lingering loathing for the language based on the 2000s era marketing, but technically speaking there's rather a lot to like about the java ecosystem.
- za3faran 4y agoJust because it started off that way does not mean it remains so. As a matter of fact, it has come along very nicely in the past few years with many cool features including virtual threads, sealed types, pattern matching, records, and more.
- beached_whale 4y agoThis should be, avoid exception catching in performance sensitive code. Assuming one isn’t doing exceptions instead of normal flow control like if/else, the dominant cost is the branch(es) to determine if there is an error to communicate. Not that there is a possible exception. Now, the catching part/after it is throw sure that is expensive in at least C++. The full stack needs to be unwound along with potential RTTI. So this becomes, do you really need that branch in the hot loop kind of problem
- kstenerud 4y agoThis 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 have stopped doing by now).
- Gigachad 4y agoSeems 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.
- polynomial 4y agoWhich is not to suggest you should be using exceptions for flow control.
- bhawks 4y agoPython's StopIteration has entered the chat.
- Izkata 4y agoI remember reading a long time ago that cpython had done some work to make exceptions lightweight enough for it to be reasonable to use them for control flow... No idea what that was though.
- TeMPOraL 4y agoWell, if that's the only "escape hatch" you have, because otherwise the language authors decided to limit what you can do with control flow...
- nosianu 4y ago> 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/2018/06/getting-the-stack-trace-versus-throwing-an-exception-what-is-common-and-what-is-different/ https://ionutbalosin.com/2018/06/getting-the-stack-trace-ver...
- AussieWog93 4y agoTIL 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!?
- phist_mcgee 4y agoIf .. Else .. Finally?
- ajkjk 4y agoIf/else statements don't bubble and exceptions do. The code samples in this example are clearly simple representations of the pattern, but the pattern is to call into a more complex function than `get_positive_value`.
- shepherdjerred 4y agoUsing 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.
- erik_seaberg 4y agoIt’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.
- gegtik 4y agoImpossible to avoid in python.. exceptions are even how a simple for loop is implemented under the covers!
- bushbaba 4y agoPython was never designed to be performance sensitive. Most of python’s high performance libraries were written in C/C++.
- kristianp 4y agoIs that still true in recent Python versions? Sounds like low-hanging fruit for perf optimisation.
- sgtnoodle 4y agoUsing exceptions in python isn't any more expensive than not using exceptions because the interpreter pays the same cost no matter what. It's a core design decision. Changing it would probably break some things.
- stevesimmons 4y agoPython 3.11 made the "try" part of exceptions zero-cost. The "except" part only has overhead if the exception is triggered.
- diarrhea 4y agoSo the answer to the question is yes, because for loops signal their finishing by raising an exception.
- tsimionescu 4y agoYes, the for loop still calls next() on the iterator until it throws a StopIteration exception.
- fsckboy 4y agoexcepts were the only way in CLU to handle control flow. something like while read_character { handle_character } except_when end_of_file { return string } and it did this primarily because it was typesafe: read_character always returned a character, and the "except" cases could return what they were declared to return. "except" was far from exceptional. There's nothing ineffecient about that, it's meatly linked up at compile/load time, and exceptions that go up the stack simply unwind the stack just as returning values up the stack do. What gets users confused is conflating this with the idea of hardware interrupts and system signals, external exceptional events that can occur at any time, interrupting the flow of control and needing registers (cpu state) to be saved so the process can be restored and continue when the interrupt is handled. (and which CLU handled through the same system) Such interrupts and signals do have a superficial resemblance to excepts that are unexceptional, and to not so unusual and recoverable errors like out-of-disk-space on a file write, which is only code you're going to write for an important high availability or headless system, or a nice fat rich word processor that people will sit in all day long. I'm just explaining this all because when I read discussions like this I'm constantly thinking "but...but... did you think of...?"
- bhawks 4y agoReturning an option sumtype is also typesafe. Exceptions have to walk up the stack until a suitable handler is found, that handler can't know ahead of time where the value is coming from or if it will ever arrive - just what type it will be if it arrives. Code emitting exceptions also have no knowledge who (if anyone) is going to handle their output. It is a nonlocal goto in reverse. Compared to regular functional returns there are so many unknowns. I'd prefer returning an option value any day of the week.
- cobbal 4y agoThat's one way to compile exceptions. There are other methods with different tradeoffs for different cases.
- tsimionescu 4y ago> Code emitting exceptions also have no knowledge who (if anyone) is going to handle their output. This is no different from code returning a regular value. When writing `return -EINVAL;` or `return 0, fmt.Errorf("")` or `return Err(something)`, you have no idea who (if anyone) is going to handle your output. Also, one reasonable way of implementing exceptions could be exactly to translate all functions that can throw exceptions to functions returning a Result type, and translating function calls to such functions to the equivalent of pattern matching on that return. Of course, this mostly forces the language to only support checked exceptions (otherwise this overhead would be added to all function calls, even those that can't actually fail). Most languages that implement exceptions have chosen a different trade-off though: make exceptions costly to throw, but make sure they have 0 cost on the happy path. Happy-path code becomes more efficient than it is possible to be in a language which uses return values for errors (since there is no need to check the result before using it), but the unhappy path becomes significantly worse.
- forgot_old_user 4y agoI'm a little disappointed that the author doesn't explain why throwing the exception is much slower.
- lolinder 4y agoStack traces. The information required to build a stack trace is deliberately kept off the critical path so it doesn't impact performance during normal operation, but that means that building a stack trace requires going out and fetching the debug symbols and correlating them. Without stack traces, exceptions are just a type of goto.
- aprdm 4y agoWhat about dynamic languages? Are they always collecting the stack and keeping it into some exception object that the exception can grab the data from at any time? And if that's the case wouldn't it always be slow regardless of raising or not ?
- lolinder 4y agoA performant dynamic language won't bundle the debug symbols either, so my assumption would be that the performance of an exception would still be bad.
- tsimionescu 4y agoWhile you are absolutely right that collecting stack traces is an extremely costly operation, it's not the only problem. For example, in C++, which doesn't collect any kind of stack trace, throwing an exception is still ~1 order of magnitude slower than returning a value through all the layers. Note that this cost only happens when the exception is thrown; exception-based code is otherwise slightly faster than `if ret < 0` style C code, as the check is entirely omitted. There is some explanation as to why this happens in this SO response [0]. The gist is that the dynamic nature of exception handling means that the compiler needs to consult runtime type information to decide where to jump when the exception is thrown, which means trawling through some relatively lengthy data structures. Adding to the problem, these data structures are not normally used a lot, so they are very likely not to be cached - though this may change for a program that actually throws exceptions in a hot loop, and the difference may not be as stark. [0] https://stackoverflow.com/questions/13835817/are-exceptions-in-c-really-slow https://stackoverflow.com/questions/13835817/are-exceptions-...
- UncleOxidant 4y agoDefinitely 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.
- shadytrees 4y agoYes, raising an exn in OCaml is close to jumping to an address stored in a register. https://stackoverflow.com/a/8567429 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/ae169dc8097b3da8e99d1baf11ebe5eb8da01dc7/src/container.ml#L30 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-notes.html#runtime-system 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.
- olliej 4y agoThis is a real problem with C++ exceptions - so much effort has gone into making them "free if you don't use them" that any time you do use them the perf is horrific. This means even reasonable "control flow" cases like network errors for example can be terrible. The more general case - and the real thing this article is complaining about - is the use of exceptions for normal control flow, which is something I agree is awful (aeons ago exceptions under .net's debugger were orders of magnitude slower than outside the debugger, but it meant that if you tried to debug logic involving an ANTLR generated parser your life was misery as - at least then - ANTLR used exceptions for parser control flow \o/)
- mindwok 4y agoExceptions 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.
- lolinder 4y agoI 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".
- lmm 4y ago> 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 Java's type system was far too weak for that to be at all practical. Early Java not only didn't have first-class functions, it didn't even have generics. Even today checked exceptions are horribly cumbersome - for example, it's simply not possible to write a wrapper function that accepts a function and calls it, and throws the same set of checked exceptions that the inner function does. If Java had had proper ML-style types from day 1, like Rust does, then it could have done "errors are values" in a practical way. But forcing people to use checked exceptions would have resulted in either C-style errno codes, or the whole language collapsing under its own weight.
- gpderetta 4y agoYes, checked exceptions with a proper type system and abstraction facilities would be completely equivalent to Result<T,E>, except built into the language.
- eyelidlessness 4y agoFor 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.
- waynecochran 4y agoI remember programming in Ada in my undergrad years and using exceptions for control flow was a common idiom. It was only later and in other languages that exceptions were treated purely as error conditions. Using exceptions allows you to separate corner cases from the normal logic. This was very clean -- not ugly as the author infers. His example is ugly, but is a straw man example.
- pixelfarmer 4y agoIt depends on how this is converted into machine level code. In quite a few cases it breaks down into rather ugly hacks, which is what creates the notion that they are "expensive" (and they are in these cases), and concluding from that should only be used sparingly, especially in code which is performance sensitive. With a sane ABI that includes exceptions as part of the daily life, so to speak, it is also possible to shift normal control flow to them without having any (larger) performance impact from it.
- danielodievich 4y agoThis is one of my basic interview questions to candidates and it is amazing how many people have no idea how exceptions work or how much they cost. Back in 2005, I was involved in a replatforming of the legacy COBOL and TRANSACT HP3000 mainframe codebase to the modern system. The code was transpiled into an [unholy mess of] C# and ASP.NET. The Transact code was extremely procedural and had mainframe forms interspread in it. Each block of code that ran between the form display and wait for input block turned into a function in C#, and all of them were chained in the main function with gotos. To get out of the function, the transpiled code would throw new Exception("with some custom message indicating step to go to next"), it'll be caught upstack, message parsed and then goto'ed to that. So yeah, control flow with Exceptions I am shuddering just thinking about it now, it was impossible to read. Under medium load - and I was in charge of load testing - it threw some astronomical numbers of exceptions/sec and it was just so ugly. Try as I might I couldn't dissuade them to change the ways they returned from the function. It all went to production. The customer just threw really big machines and lots of them and they just exceptioned all day long.
- gpderetta 4y agoThat seems exceptionally bad!
- commandlinefan 4y agoThey did try though.
- zefei 4y agoI think what the article is addressing is likely not what is being discussed in this thread. The article ("Unfortunately, I often see solutions abusing exceptions" followed by using exceptions to replace if statements) is very likely discussing poor understanding of the topic from student assignment rather than actual code in the industry. Such mistakes (abuse of exceptions in the article) often go away once students become actual professionals because these mistakes are more easily caught during code review than other types of common mistakes.
- kajaktum 4y agoNot having exception is not having incorrect code i.e. code that does not throw. This is very hard to do in languages that naturally throws exception like Java or C/C++. If you have errors as part of the contract however...now you can be sure (or surer) that the function you are calling does not fail.
- mcqueenjordan 4y agoI think most serious C++ shops are probably compiling with -fno-exceptions.
- tsimionescu 4y agoThat is entirely false. You can barely even use half the language without exceptions.
- mcqueenjordan 4y agoI 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. ;)
- galangalalgol 4y agoMore 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?
- w0mbat 4y agoPersonally, I'd say "Avoid exceptions" and leave it at that.
- europeanguy 4y agoIn python, exceptions for control flow is how the language works. Think about that.
- felixmeziere 4y agoThank you! Was starting to think I got all my codebase wrong and misunderstood what is « pythonic » So doing this in python is ok (fastest way to check if a key is in a dict is catching KeyError for example, if I remember correctly)
- papito 4y agoYes, do not let the HN anti-exception crusaders gaslight you. I still remember when I "discovered" exceptions in programming - "this is so much cleaner!" All this theoretical mumbo jumbo is just noise. Very few of us are dealing with the type of programming every day where exceptions can actually become a noticeable bottleneck.
- thisishard 4y agoHere's another link about the problems with C++ exception that I find very insightful https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2544r0.html https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p25... The major issue that stood out to me is that in a multi-threaded environment, exception unwinding is effectively single-threaded. This means that if you have C++ code that throws a lot of exceptions, you are going to see a lot of threads getting blocked by lock contention
- gpderetta 4y agoto be clear, the single-threaded behaviour of some implementations is, well, implementation specific. There is nothing in the C++ standard that requires that. In particular, for GCC under linux, the issue is that the unwinder need to parse the unwind tables and needs to protect itself from a concurrent ldclose yanking them under it. There is some work currently on GCC to move this cost from unwinding to ldclose and allow concurrent unwinding without breaking the ABI (but it is hard).
- yawboakye 4y agoumm the example is contrived, and the title is overly broad. performance-sensitive code has exceptional situations that can either be handled, or should cause the program to abort. performance-sensitive code use libraries that throw exceptions too. or the recommendation here will be to use non-exception-throwing libraries only in performance-sensitive code? that significantly reduces what libraries i can use in my code. my interpretation of the essay is: where possible prefer is/else to try/catch. branching on if/else is easy and inexpensive. try/catch could be expensive if (1) new exception instance is created every time, (2) stack/backtrace is generated. you really want to avoid (2) when all you need from the exception is the information that the abnormal happened. if you can use a singleton exception, you may be able to use try/catch. then you can make the beauty (of the code) judgement later.
- cgrealy 4y agoThis 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.
- groestl 4y ago99.99% (maybe even more) of game engines is not performance critical code though. I guess the reason was a different one: for exceptions to work you need a sane memory model. It's very hard to write exception safe code in C++. A garbage collector is very helpful to accomplish that, and _this_ is the thing that's problematic, because it interferes with the 0.01% performance critical inner loops.
- Vogtinator 4y ago> It's very hard to write exception safe code in C++. How? As long as RAII is used it's basically for free.
- summerlight 4y agoBut there are a bunch of codes which are yet to be verified as exception-safe. And in the gaming industry it's often third party code that you cannot even inspect.
- gpderetta 4y agoThe right statement is then that it is very hard to retrofit exceptions in an non-exception safe code base. Exception safety itself is not easy, as it requires different code patterns and idioms than usual. I believe that those idioms are useful and great even for non-exceptional code, but that's another story.
- groestl 4y agoI agree and would replace my original statment of "It's very hard to write exception safe code in C++" with this.
- a-dub 4y agoi wonder how feasible it would be to implement a syntax coloring mode that provides some indication of instruction count from static analysis. so not quite dynamic profiling, but rather something that uncovers (sometimes) surprising implementation details like this and creates a better sense for what the compiler is doing under the hood.
- jillesvangurp 4y agoMaybe "don't use exceptions for conditional logic" would be a better way of phrasing this. If exceptions become a performance bottleneck, there's nothing exceptional about them anymore.
- chrismorgan 4y agoI’m curious if there are ecosystems where get_positive_value would be a reasonable name for the method described. I’d expect something like assert_positive, or check_is_positive, or throw_if_negative. I admit these would suggest returning void rather than int, but “get” just isn’t right either in the ecosystems I’m familiar with (e.g. Rust, Python, JavaScript).
- janosdebugs 4y agoThe author mentions Go, but Go has "exceptions" too in the form of panics. I tested the speed of throwing panics, and if the error type evaluation is involved, the panics don't lag behind returning errors one bit. I even created an experimental library to support this in a playground project: https://github.com/apitalist/lang https://github.com/apitalist/lang
- ilyt 4y ago>Unfortunately, I often see solutions abusing exceptions: int sum = 0; for (int x : a) { try { sum += get_positive_value(x); } catch (...) { sum += -x; } } you need to fire whoever does that...
- j0057 4y ago"Avoid using exceptions for control flow" is unhelpful advice because it is a paradox: exceptions ARE control flow.
- tsss 4y agoMore advanced languages like Koka or Eff use exception-like functionality for _every_ side effect. Every IO, every log statement, practically everything and they perform fine.
- commandlinefan 4y ago> I often see solutions abusing exceptions Wow, I thought I had seen bad code, but even I've never seen this. My condolences, OP.
- MrYellowP 4y agoI 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!