I am working on porting a Java codebase to Cocoa/Objective-C for use on desktop Mac OS X. The Java code has lots and lots of methods with checked exceptions like:
double asNumber() throws FooException {
...
}
What's the best way to represent these in Objective-C? Exceptions or error out-parameters?
- (CGFloat)asNumber {
... // possibly [FooException raise:format:];
}
or
- (CGFloat)asNumberError:(NSError **)outError {
...
}
I have the sense that out-errors are generally the better solution for Objective-C, but as you can see... a lot of methods like the one above will be quite awkward-looking. And again, there are lots of these.
Of course keep in mind that since these are checked exceptions in Java, I will need to add either @try
blocks or if (*outError) {...}
checks wherever these methods are called (lots of places).
I recall hearing that while entering @try
blocks was once expensive in Objective-C, it is cheap in 64-bit or SL or some other new env (don't recall exactly). I am not at all concerned about backwards compatibility, so i am definitely willing to design only for the new hotness.
A checked exception must be handled either by re-throwing or with a try catch block, whereas an unchecked isn't required to be handled. A runtime exception is a programming error and is fatal whereas a checked exception is an exception condition within your code's logic and can be recovered or re-tried from.
A checked exception is a type of exception that must be either caught or declared in the method in which it is thrown. For example, the java.io.IOException is a checked exception.
Because the Java programming language does not require methods to catch or to specify unchecked exceptions ( RuntimeException , Error , and their subclasses), programmers may be tempted to write code that throws only unchecked exceptions or to make all their exception subclasses inherit from RuntimeException .
The Throwable class is the superclass of all Java exceptions and errors. It has two subclasses, Error and Exception but they don't represent checked and unchecked exceptions. The Exception class has a subclass called RuntimeException that contains most unchecked exceptions.
Java verifies checked exceptions at compile-time. Therefore, we should use the throws keyword to declare a checked exception: We can also use a try-catch block to handle a checked exception: Some common checked exceptions in Java are IOException, SQLException and ParseException.
The RuntimeException class is the superclass of all unchecked exceptions, so we can create a custom unchecked exception by extending RuntimeException: 4. When to Use Checked Exceptions and Unchecked Exceptions It's a good practice to use exceptions in Java so that we can separate error-handling code from regular code.
These types of Exceptions occur during the runtime of the program. These are the exceptions that are not checked at a compiled time by the compiler. In Java exceptions under Error and Runtime Exception classes are unchecked exceptions, This Exception occurs due to bad programming.
Checked exceptions are the subclass of the Exception class. These types of exceptions occur during the compile time of the program. These exceptions can be handled by the try-catch block otherwise the program will give a compilation error. ClassNotFoundException, IOException, SQLException etc are the examples of the checked exceptions.
You should definitely avoid exceptions for things like parsing numbers from strings. In Objective-C, exceptions represent programmer error, not user input error, or even unavailable files. (Part of the reason is that exception handling is always more costly and complex than more "conventional" error handling. Regardless of the fact that entering @try
blocks is "zero cost" in 64-bit, it's still slow whenever an exception is actually raised.) Of course, you're allowed to use exceptions as you like, but it's not the Cocoa way, and you'll find yourself at odds with other Objective-C code. People who use your code will be incredibly annoyed that you throw exceptions in cases that should just result in an error.
From Apple's own docs:
"In many environments, use of exceptions is fairly commonplace. For example, you might throw an exception to signal that a routine could not execute normally—such as when a file is missing or data could not be parsed correctly. Exceptions are resource-intensive in Objective-C. You should not use exceptions for general flow-control, or simply to signify errors. Instead you should use the return value of a method or function to indicate that an error has occurred, and provide information about the problem in an error object."
Look at how built-in Cocoa classes handle errors like this. For example, NSString has methods like -floatValue
that return 0 if it fails. A better solution for your particular situation might be how NSScanner does it, such as in -scanFloat:
— accept a pointer to the field where the result should be stored, and return YES
or NO
based on whether the parse was successful.
Aside from Obejctive-C convention and best practices, NSError is much more robust and flexibly than NSException, and allows the caller to effectively ignore the problem if they want to. I suggest reading through the Error Handling Programming Guide For Cocoa. Note: If you accept an NSError**
param, I strongly suggest you also design to allow the client to pass NULL
if they don't want to receive any error information. Every Cocoa class I'm aware of does this for errors, including NSString.
Although the ported code may end up looking totally different from the Java code, recognize that it will be used by Objective-C code, not the same clients of the Java equivalent. Definitely match the idioms of the language. The port will not be a mirror image of the Java code, but it will be much more correct (for Objective-C) as a result.
In Cocoa, exceptions are really only supposed to be used for "programming errors;" the philosophy is to let the app catch them, give the user the option to save what they're doing, and quit. For one thing, not all frameworks or code paths may be 100% exception-safe, so this can be the only safe course of action. For errors that can be anticipated and recovered from, you should use NSError, typically via an out-parameter.
You're correct that "out errors are generally the better solution for ObjC". Very rarely will you find an API in Cocoa that throws an exception (unless you haven't satisfied the preconditions for the API, but in that case, behavior is undefined by default).
If you expect this code to live beyond you and be adopted by other Cocoa developers, I would recommend using out errors. I work on code that was built by people unfamiliar with Cocoa and who used exceptions liberally, and they're a royal pain to work around.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With