mikeash.com pyblog/friday-qa-2017-08-25-swift-error-handling-implementation.html commentshttp://www.mikeash.com/?page=pyblog/friday-qa-2017-08-25-swift-error-handling-implementation.html#commentsmikeash.com Recent CommentsFri, 29 Mar 2024 13:32:17 GMTPyRSS2Gen-1.0.0http://blogs.law.harvard.edu/tech/rssColton - 2019-12-30 19:07:18http://www.mikeash.com/?page=pyblog/friday-qa-2017-08-25-swift-error-handling-implementation.html#comments@Max swift only needs the one jump to the catch code. Whereas c++ has to crawl up the stack and check the error handling tables. <br /> <br /><div class="blogcommentquote"><div class="blogcommentquoteinner"> <br />How can this possibly work? In addition to generating the no-exceptions code, the compiler also generates a table with information about how (and whether) the code handles exceptions and how to safely unwind the stack to exit out of the function in the event that an exception is thrown. <br /> <br />When some function throws an exception, it walks up the stack, looking up each function's information and using that to unwind the stack to the next function, until it either finds an exception handler or runs off the end. If it finds an exception handler, it transfers control to that handler which then runs the code in the catch block. <br /></div></div> <br /><div class="blogcommentquote"><div class="blogcommentquoteinner"> <br />When an exception is thrown, the concept of "zero-cost" goes out the window. Unwinding the stack using the tables is an expensive process and takes a substantial amount of time. <br /></div></div>b6080ad89e0bd5769a09e9d2d6ae6384Mon, 30 Dec 2019 19:07:18 GMTMax - 2019-12-25 08:24:44http://www.mikeash.com/?page=pyblog/friday-qa-2017-08-25-swift-error-handling-implementation.html#commentsYou point out that when exceptions are <b>not</b> thrown, the <code>throw</code> functions in Swift are (typically very slightly) slower than in C++ . <br /> <br />IIUC, the note at <a href="https://docs.swift.org/swift-book/LanguageGuide/ErrorHandling.html">https://docs.swift.org/swift-book/LanguageGuide/ErrorHandling.html</a> (under Handling Errors section) says that when exceptions <b>are</b> thrown, Swift is faster than C++. Why is it so? I understand that Swift can find out whether an exception occurred simply by reading a register; but then doesn't it still have to jump to the calling function frame, just like in C++? And wouldn't that jump be just as expensive as in C++? <br />302df5f928c790d255d6d2530674973aWed, 25 Dec 2019 08:24:44 GMTmikeash - 2018-07-24 23:55:04http://www.mikeash.com/?page=pyblog/friday-qa-2017-08-25-swift-error-handling-implementation.html#commentsThe OS maintains the illusion that each thread has its own set of registers. Whenever the OS stops a thread, it saves its register state into memory along with other info about the thread. When the OS resumes that thread, it restores the register state. Multiple threads will share registers, but they never know it.ed73e1f0f93bbe23cf904d7b9df14450Tue, 24 Jul 2018 23:55:04 GMTsanthosh - 2018-07-20 07:58:49http://www.mikeash.com/?page=pyblog/friday-qa-2017-08-25-swift-error-handling-implementation.html#commentsHow does this work when multiple threads are running? I am assuming that there will be only one such register.b63eb492885a8e41dc9695db1bb5be12Fri, 20 Jul 2018 07:58:49 GMTmikeash - 2017-08-29 17:12:22http://www.mikeash.com/?page=pyblog/friday-qa-2017-08-25-swift-error-handling-implementation.html#comments<b>Thomas Tempelmann:</b> There's no such thing as an unhandled error in Swift. You're only allowed to write <code>throw</code> or <code>try</code> in a context where it's guaranteed that something will catch it. <br /> <br />If you want to be able to throw from anywhere and catch at the top level, then all of your functions would need to be declared as <code>throws</code>. Which of course you could do, if you wanted to! If you wanted to take it to an extreme, you could write versions of force-unwrapping, subscripting, division, etc. that throw rather than crashing when their preconditions are violated. <br /> <br />I don't think top-level exception handlers, and throwing exceptions for every single error, is a good idea. We should distinguish between programmer errors and external errors. Programmer errors can't be anticipated in code, pretty much by definition. Any attempt to handle them is fraught with peril. If, for example, some <code>Optional</code> contains <code>nil</code> when you thought it couldn't possibly do so, what else is wrong with the state in your program? Trying to continue is a potential disaster. <br /> <br />External errors are things like disk failures, network failures, or badly formatted data. These you can anticipate and deal with in code. To do it properly, you need to test all of that error handling code with the failures you've written it to handle. <br /> <br />If the goal is better diagnostics for users when they hit bugs, I think the best bet is to crash on failure, and use some sort of crash reporting tool to get the stack traces to you.a54174302755b4ce09ee6d32e968f2e3Tue, 29 Aug 2017 17:12:22 GMTThomas Tempelmann - 2017-08-26 18:19:56http://www.mikeash.com/?page=pyblog/friday-qa-2017-08-25-swift-error-handling-implementation.html#commentsSo, what about stack traces for unhandled exceptions - how'd I do that? <br /> <br />I.e., in my apps (I often write code in C++ and Xojo, formerly RealBasic) I like to be able to throw an exc in deep functions if something is wrong, and since these languages do not force me to write a catch handler at every level (unlike Java and Swift), I end up with writing exception handlers at the top level (i.e. where an event originates, though, Xojo makes this especially easy by forwarding all unhandled exceptions to the initial Application object), where I'd then write a log file and tell the user that something went wrong. That log file would then optionally sent by the user to me, so that I could figure out where and possibly why something went wrong there. <br /> <br />This error log would include a stack trace because Xojo would include the stack trace on a throw, (and C++, well, see this, for example: <a href="https://stackoverflow.com/a/26883211/43615">https://stackoverflow.com/a/26883211/43615</a>). <br /> <br />Of course, the advantage in Xojo is that even the runtime uses exceptions when reporting things like null pointers, out-of-bounds errors (for array access, for instance) and other low level errors. Swift doesn't do that, unfortunately (and I understand the reasoning behind some of it, but not all - I still want back a language that throws when encountering a div-by-zero or a value overflow in an expression or assignment). <br /> <br />So I wonder if I should change my programming paradigms and stop using exceptions for reporting unexpected states, or if I keep using them, whether I'll lose the ability to catch them at the highest level, along with learning the stack trace? <br />1e21c12a06b7b7de86a0e99ed5217696Sat, 26 Aug 2017 18:19:56 GMTJoe Groff - 2017-08-25 16:55:21http://www.mikeash.com/?page=pyblog/friday-qa-2017-08-25-swift-error-handling-implementation.html#commentsWe had planned from the beginning to have a special calling convention for error handling, but the LLVM backend work didn't land until last year. One of the arguments against manual propagation of errors has long been the code size and performance cost at each call, but Swift's ABI does a pretty good job of minimizing the cost without getting too avant-gardeā€”it's one instruction to zero out the error register at the boundary where you enter a "throws" context, and one instruction (on ARM64 at least, though still one fused uop on Intel) to jump-if-not-zero into the catch block after each call that might throw.dab6d0d07a4e4ac9e1815925d0db9ed4Fri, 25 Aug 2017 16:55:21 GMTmikeash - 2017-08-25 16:49:03http://www.mikeash.com/?page=pyblog/friday-qa-2017-08-25-swift-error-handling-implementation.html#comments<b>Joe Groff:</b> Nice! I suspected that was the case when I looked at it, but didn't want to go too crazy with speculation in the article. What was the reason for switching away from the extra "out" parameter as done in Swift 3? Just a performance thing?22d047ed7c2809dd55630f8253301b81Fri, 25 Aug 2017 16:49:03 GMTJoe Groff - 2017-08-25 16:46:58http://www.mikeash.com/?page=pyblog/friday-qa-2017-08-25-swift-error-handling-implementation.html#commentsSome more fun trivia: r12 and x21 were specifically chosen because they're normally callee-saved registers, so a non-throwing function can be "toll-free bridged" as a throwing one, since the non-throwing ABI will always preserve null in the error register.0854d02f253027c55ed28d81078c2c81Fri, 25 Aug 2017 16:46:58 GMTmikeash - 2017-08-25 15:59:54http://www.mikeash.com/?page=pyblog/friday-qa-2017-08-25-swift-error-handling-implementation.html#comments<b>Tinus:</b> Indeed, you still have to pay for the space. The term "zero-cost" just refers to runtime execution overhead.c1c3d3a55cb7bc3774adb697f2996f9eFri, 25 Aug 2017 15:59:54 GMTTinus - 2017-08-25 14:44:35http://www.mikeash.com/?page=pyblog/friday-qa-2017-08-25-swift-error-handling-implementation.html#commentsIt can't be free to store the unwind code (in c++), can it?4e5abd2b9a4194f23be0758d774f8710Fri, 25 Aug 2017 14:44:35 GMT