Swift vs Obj-C exceptions. What is stack unwinding? Why doesn't Swift do it? - objective-c

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.

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

Related

Unexpected leak caused by #throw in block [duplicate]

I am thinking about pros and cons of Try-Catch in Objective-C.
According to this article Dispelling NSException Myths in iOS: Can We Use #try…#catch, #finally?, try-catch isn't that bad, except for it leaks memory in ARC.
So how does try-catch cause memory leak?
First of all: Exceptions have different semantics in Objective-C. An exception means that something went completely wrong because of a programming mistake and the further execution of the application is not useful. Terminate it! To handle "expected errors" (like insufficient user input or not responding servers et al.) use Cocoa's error handling pattern. (The reason for this is that exceptions seems to be convenient in many situation, but are very hard to handle in other situations, i. e. while object construction. Read about exceptions in C++. It is painful.)
To your Q: ARC adds additional code to handle memory management. This code has to be executed to handle the memory management, esp. to release objects. If an exception occurs before this is done, the control flow never reaches the release statement. Memory leaks.
- (void)method
{
id reference = …;
// Some ARC code to retain the object, reference points to.
…
#throw …
…
// reference loses its extent, because of method termination
// Some ARC code to release the object, reference points to.
}
If you have an exception, the method is left immediately and the ARC code and the end of the method to release the object is never executed. This is the leak.
You can change this behavior by compiling the source with -fobjc-arc-exceptions option.
http://clang.llvm.org/docs/AutomaticReferenceCounting.html#exceptions
This will add code to make ARC exception-safe causing a runtime penalty. But there is little reason to do so in Cocoa development, as explained at the beginning of this answer.

Why does NSOperation example code uses #try & #catch

In Apple's Concurrency Programming Guide the NSOperation subclass examples (both non-concurrent and concurrent varieties) use exception handling and I'm wondering why they are encouraging this style within operations.
Listing 2-4 Responding to a cancellation request
- (void)main {
#try {
BOOL isDone = NO;
while (![self isCancelled] && !isDone) {
// Do some work and set isDone to YES when finished
}
}
#catch(...) {
// Do not rethrow exceptions.
}
}
My understanding is that generally exception handling is not a common practice in Objective-C code - exceptions are essentially programmer errors and should cause the app to crash whereas unexpected inputs are best handled by NSError. (My possibly misinformed understanding comes from things like this and this)
I'm wondering if NSOperations present a particular situation in which exception handling is important, or if this is more the preferred style of the particular author of that guide.
As a side note, some of the NSOperation example code follows this style, other examples do not. Most high-visibility OSS does not use exceptions (AFNetworking, for example).
Your understanding is correct - NSError (or similar) should be used to convey error information, rather than exceptions. Most Objective-C code is not exception-safe and will at the very least leak resources. As a general rule, never let your code leak an exception into anyone else's code - whether Apple's or a 3rd parties. Some 3rd party frameworks may explicitly indicate they are exception safe, but it's rare.
By that principle you can see why you should have a catch-all exception handler in your main method regardless. But there's actually another reason: your operation will be run on a dedicated thread. Exceptions thrown from your operation will propagate up the stack, but no further. The logical caller or owner of the operation won't get them, as they're running on a different thread (or not at all). So leaked exceptions will either kill your whole program, or be swallowed silently with no other indication. Your program may then get stuck in a weird state - since you didn't realise an error occurred, you may continue waiting for the result of your operation that will never arrive.
Additionally, Apple has a section in the Concurrency Programming Guide where they talk about Handling Errors and Exceptions. Their first point on "discrete entities" is alluding to what I said in the previous paragraph:
Handling Errors and Exceptions
Because operations are essentially
discrete entities inside your application, they are responsible for
handling any errors or exceptions that arise. In OS X v10.6 and later,
the default start method provided by the NSOperation class does not
catch exceptions. (In OS X v10.5, the start method does catch and
suppress exceptions.) Your own code should always catch and suppress
exceptions directly. It should also check error codes and notify the
appropriate parts of your application as needed. And if you replace
the start method, you must similarly catch any exceptions in your
custom implementation to prevent them from leaving the scope of the
underlying thread.
Among the types of error situations you should be prepared to handle
are the following:
Check and handle UNIX errno-style error codes.
Check explicit error
codes returned by methods and functions.
Catch exceptions thrown by
your own code or by other system frameworks.
Catch exceptions thrown
by the NSOperation class itself, which throws exceptions in the
following situations:
When the operation is not ready to execute but
its start method is called
When the operation is executing or finished
(possibly because it was canceled) and its start method is called
again
When you try to add a completion block to an operation that is
already executing or finished
When you try to retrieve the result of
an NSInvocationOperation object that was canceled
If your custom code
does encounter an exception or error, you should take whatever steps
are needed to propagate that error to the rest of your application.
The NSOperation class does not provide explicit methods for passing
along error result codes or exceptions to other parts of your
application. Therefore, if such information is important to your
application, you must provide the necessary code.
I think this post and the accompanying answer elaborates very well on the general exception- vs. no exception handling topic!
It is unsafe to throw exceptions in circumstances where resources are
not automatically managed. This is the case of the Cocoa framework
(and neighbor frameworks), as they use manual reference counting.
If you throw an exception, any release call you skip over by unwinding
the stack will result in a leak. This should limit you tothrowing only
if you're certain that you're not going to recover since all resources
are returned to the OS when a process quits.
Unfortunately, NSRunLoops tend to catch all exceptions that propagate
to them, so if you throw during an event, you'll resume to the next
event. This is, obviously, very bad. Therefore, it's better that you
simply don't throw.
This problem is diminished if you use garbage-collected Objective-C,
as any resource represented by an Objective-C object will be properly
released. However, C resources (such as file descriptors or
malloc-allocated memory) that are not wrapped in an Objective-C object
will still leak.
So, all in all, don't throw.
The Cocoa API has several workarounds to this, as you mentioned.
Returning nil and the NSError** pattern are two of them.

NSException and NSError custom exception/error

I recently started learning Objective-C, and I am working on an iOS app as an exercise, anyway, I want to handle overflow by throwing exception (I come from a Java background), I searched the reference there is only NSException, but then I read in the section that say topics about exception handling, and they said to use NSError, I read the reference but they had the same protocol and methods, so what's the difference between them? And which is better?
Also, I want to create my own exception or error class, are there any methods or fields that I should include? (Like when implementing the Exception interface in Java).
Thanks
NSError is designed for non-fatal, recoverable errors. The problems that are designed to be captured by an NSError are often user errors (or are errors that can be presented to the user), can often be recovered from (hence -presentError: and NSErrorRecoveryAttempting), and are usually expected or predictable errors (like trying to open a file that you don't have access to, or trying to convert between incompatible string encodings).
NSException is designed for potentially fatal, programmer errors. These errors are designed to signify potential flaws in your application where you have not correctly checked the pre-conditions for performing some operations (like trying to access an array index that is beyond its bounds, or attempts to mutate an immutable object). The introduction to the Exception Programming Guide explains this a little bit.

Using exceptions in Objective-C

I'm new to Objective-C world. What I have noticed while studying some iOS/Mac apps is that try -catch is rarely used, if used at all.
For example in Java it is used almost all the time.
Why isn't it so common in Objective-C ?
Exceptions in Objective-C are generally to be used for truly exceptional circumstances and almost always programmer error. To convey a recoverable error use the NSError** pattern.
There are a lot of SDK methods that take an NSError** parameter and return BOOL. To indicate an error they return false and feed an error back through the error parameter to communicate info.
Exceptions are used, but generally for cases in which there is some failure at the runtime level - e.g. some object can't handle a selector. Although it may seem contrary to what I just wrote, exceptions tend to indicate an error in design rather than a runtime error.
The NSError** idiom is all you need for things such as failed URL connections, data conversions, etc, where an error condition exists but a program really shouldn't be killed outright.
Start reading: Error Handling Programming Guide

What’s the rationale behind the Cocoa exception policy - or why use exceptions only for programmer errors?

What’s the rationale behind the Cocoa exception policy - or why use exceptions only for programmer errors?
I understand that exception used to be rather expensive so one would not want to overuse them. But that changed with the modern runtime and it’s zero-cost exceptions. I also understand that the use of exceptions to do general control flow is not a good idea because it could lead to code that is rather hard to understand.
But why should one use exceptions to signal programmer errors? For that case logging a message followed by abort() should be enough. Why should I write a #catch(...) block to handle a programmer error instead of fixing the actual mistake? I’ve been thinking about this a lot and I haven’t found any reasonable use of an exception for a programmer error.
(As a side note/question: I’ve written a recursive descent parser, and I’m planning on using exceptions in there for handling errors. Seems to be much more reasonable to me than adding an out parameter to every single function in there and manually check for an error everywhere. Of course I’ll catch any exceptions I throw in the top level methods that get called from the outside. Anyone think that’s a bad use for exceptions?)
Update: The real question
Thanks for all the answers so far. They all are true, but they don’t actually answer my question. So I guess I wasn’t really clear about it, sorry for that. So here’s the real question:
Why does Cocoa throw exceptions for programmer errors (or assertions) at all? One isn’t supposed to catch them, and actually writing code that handles a programmer error somewhere down the call stack is not a good idea anyways. Seems to me that exceptions there are a wasted effort. Simply logging the error and calling abort() (which exits the program) should be enough. So what’s the advantage there of actually having an exception thrown?
I understand why exceptions are not generally used and discouraged - most parts of Cocoa are just not exception safe. And that’s not the question here. I hope I made this clear now.
Why should I write a #catch(...) block to handle a programmer error instead of fixing the actual mistake?
In most cases, you wouldn't. In Objective-C, you generally don't handle exceptions. If an exception occurs, it causes a crash, and then you fix the bug -- hopefully you catch this during testing.
Of course, in some cases this doesn't work out. Maybe you do except an exception and you can workaround it, so you catch it. Or there's there rare API that'll throw exceptions instead of using error objects.
To be honest, I very, very rarely use try/catch in my Objective-C code.
As for the rationale, I think it's largely due to Objective-C's C heritage. Back in the early 80s when Objective-C was developed, exceptions were kind of "new" (i.e., not in many mainstream languages yet), and Objective-C catered more to the C tradition of using NULL or an out parameter to signal errors.
Your question explicitly assumes that "one isn’t supposed to catch them." This is incorrect. The programmer isn't expected to catch them under normal circumstances, but that isn't to say that they must never be caught for any purpose.
Example: I'm not sure if it does anymore since it's much less buggy these days, but I know it at least used to be the case that Xcode would catch exceptions and put up a dialog saying, "Such-and-such happened. It doesn't appear to be a critical problem, but you should probably save and restart the program to avoid any trouble in the future."
Why does Cocoa throw exceptions for
programmer errors (or assertions) at
all? One isn’t supposed to catch them,
and actually writing code that handles
a programmer error somewhere down the
call stack is not a good idea anyways
Ah!
Three reasons leap to mind.
One, if you catch an exception more or less at your main run loop you could autosave state to a temporary location, crash, and on restart have a "try to restore from just before the crash, warning: may cause another crash and you should check your data very carefully" dialog/sheet/thingie. Or even just catch the exception and tell the user to do a "Save As", quit and restart.
Two, things like the unit test framework make good use of exceptions to abort the current test (logging a failure), and continuing with the rest of the tests. This lets you see if a change you made has one regression (that happens to index a NSArray out of bounds), or if you have six regressions (one or more of which throw an exception).
Three, maybe when added to ObjC it was intended to handle many kinds of errors with exceptions, and after real world experience the useful scope was determined to be "nearly fatal errors only".
The main reason for avoiding throwing exceptions is that you may accidentally throw them through stack frames that are not exception aware. For instance, if a data source for a table view throws an exception, that is not caught and handled before the delegate method returns control to the table view, it might cause all sorts of trouble as it unwinds the table view's stack frames, side stepping various releases of temporary objects and other resources.
Having said that, I personally like exceptions and use them wherever I think they are the natural thing to do, but with the caveat of never allowing them to propagate to code that is not documented as exception aware.
There are likely a lot of reasons. The "historical reasons" others have covered is sufficient to explain the current state of affairs, but there are other possibilities.
Another possibility is Objective C is not typically a "Resource Acquisition Is Initialization" kind of language (yes this is more a library issue then a language issue, but it is real). So most Objective C code that has an error thrown through it will leave invalid program state (things still locked, over retained objects). All things you could deal with if you were thinking about it, and not all things RAII would magically fix (there is a lot of exception unsafe C++ code out there, and C++ is largely RAII).
As noted above stating that you do handle an exception is free(ish), but actually having one thrown is costly (maybe an order of magnitude or two more costly then an extra parameter and a conditional check). So if your parser (for example) uses them to signal errors in parsing, being given a document with a lot of errors can take a LOT longer to parse then if you had explicit checks for an error parameter.
Personally I like exceptions, and would prefer to throw exceptions from my libraries when things "go wrong", but that isn't the Cocoa way, so I use exceptions to handle programmer errors and an error indication and NSError** for other things. It isn't great, but it makes it so other people can use my libraries without having to learn a new way to write Objective C code.
The modern runtime does not give you zero-cost exceptions, it gives you exceptions that only incur their cost if an exception is thrown.