9

There is a note in the Swift Docs that states the following:

Error handling in Swift resembles exception handling in other languages, with the use of the try, catch and throw keywords. Unlike exception handling in many languages—including Objective-C—error handling in Swift does not involve unwinding the call stack, a process that can be computationally expensive. As such, the performance characteristics of a throw statement are comparable to those of a return statement.

What does unwinding the call stack mean in Swift and Obj-c? Related question here but it is C++ specific. I know what the call stack is, but would like a more detailed explanation of unwinding.

If Swift doesn't unwind the call stack, what does it do instead?

Why can this be computationally expensive?

Summed up: I'd like to get a better understanding of how exceptions work and the execution flow in Swift.

Community
  • 1
  • 1
Brynjar
  • 1,252
  • 1
  • 11
  • 24

1 Answers1

5

Unwinding the stack basically means that when an exception is thrown, the method is immediately interrupted, the caller of the method is immediately interrupted and so on until an exception handler (try-catch-finally) is found or until we reach the top of the stack, when the exception usually ends in interrupting the current thread.

That works pretty well in languages with a garbage collector but in general it can lead to memory leaks in languages with manual memory management. Also, since methods are interrupted in unexpected places, an exception often leads to undefined/unrecoverable program states.

That's why exception in all languages should be used sparingly and only to handle exceptional situations, not to handle normal program flow.

Obj-C exceptions weren't very good, with all the problems mentioned above (see NSException, @try-@catch-@finally), that's why nobody is using them. Instead, Obj-C came with error parameters (you pass a reference to a NSError variable and if the method fails, the error gets assigned into that variable). See Error Handling in Objective-C

Swift just came with another syntax for NSError. It's not a real exception handling (errors don't interrupt program execution). See Error Handling in Swift

Technically, every function/method that can throw an error in Swift only has an additional hidden parameter that is used to pass the error back to caller context.

If you want more information, just compare code in Swift 1.x and 2.x (1.x didn't have special grammar for error handling yet).

Sulthan
  • 128,090
  • 22
  • 218
  • 270
  • 2
    What I never got: Returning from a function *leads* to stack unwinding. Of course, step-by-step (aka call-by-call). But I cannot realize, why this is less expensive. – Amin Negm-Awad Apr 05 '16 at 11:27
  • @AminNegm-Awad Really measuring performance is not easy, every language and every compiler use a slightly different model. You can see http://stackoverflow.com/questions/13835817/are-exceptions-in-c-really-slow for example. Note the performance impact is important when the exception actually happens. Another reason to never use exceptions for normal program flow. Also keep in mind that a programming language that does not use exceptions at all can be optimized much better by the compiler, leading to even better performance. – Sulthan Apr 05 '16 at 11:46
  • 2
    @Sulthan Your answer has helped thanks, but you mention Swift has a hidden param it can pass back. I don't see how this is different from stack unwinding? If I call a func one() which calls func two() and two throws an exception that neither one nor two handles, I have to handle it in my calling code. But any statements after the call to try two() in one aren't executed. Isn't that unwinding the stack back to the caller? Then execution continues from the caller's next statement in the catch block. – Brynjar Apr 05 '16 at 13:58
  • @sulthan AFAIK Objective-C took over the C++ exception system for better integrity some years ago. And AFAIK Objective-C's memory management (ARC) simply does not care about exceptions by default, so there are 0 costs and full optimizations for ARC. I know the general caveats of exceptions. I do not understand, why Swift can take an advantage out of it. (BTW: Objective-C, more precise Cocoa, did not use an exception-based error handling from the very beginning for many reasons, esp. bad control flow prediction for the developer. This applies to Swift, too.) – Amin Negm-Awad Apr 05 '16 at 14:37
  • To me it sounds like a marketing lie of Swift as we know that from many other so called features: It simply copies Cocoa's error handling, call it differently, put some obfuscation on top of it, say that it is better and don't let us verify that. – Amin Negm-Awad Apr 05 '16 at 14:39
  • @AminNegm-Awad I don't know about any Swift "feature" that I would call a marketing lie. I am not saying that C++ exception handling is better or worse than the error handling in Swift but it's definitely much more complicated, needs special processor instructions (there is a reason why some C++ implementations don't support exceptions) and cannot work with memory management based on reference counting. Error handling based on return values (especially when error handling is enforced by syntax) is much lighter and it has *huge implications* on program predictability. – Sulthan Apr 05 '16 at 15:24
  • What is the difference to Cocoa's return + param-out pattern? – Amin Negm-Awad Apr 05 '16 at 16:24
  • @Sulthan Are you planning to address my comment about the stack unwinding so I can then mark this question as resolved? Thanks. – Brynjar Apr 08 '16 at 07:51