Can I restrict the type that a function throws in Swift? - swift

When calling a function in Swift 3 that throws, you have to be exhaustive in catching all possible errors, which often means you have an unnecessary extra catch {} at the end to handle errors that won't happen.
Is it possible to say throws MyErrorType so that the compiler can know you have indeed been exhaustive when you handle all cases from that enumeration?

There's no simple way to be type-safe with thrown errors. Consider this, if the compiler allowed you to specify throws MyErrorType, then it would also have to ensure within that function body that you're not trying a function that could potentially throw a different type outside of a do/catch block. (Well there is but it would add layers of unnecessary complexity). The Swift compiler can already be slow and get stuck in loops when inferring types, inferring Thrown types all the way up a chain of throwing functions could be a nightmare.
The running idea is that for most errors you're going to handle them in a small subset of ways anyhow.
That being said, there's no need for you to add extra catch let error as MyErrorType clauses, you can simply use a switch in a catch block like so:
do {
try something()
} catch let e {
switch e {
case let m as MyErrorType: handleMyError(m)
case let o as OtherErrorType: handleOther(o)
case is ThirdErrorType: print("error \(e)")
default: handleElse(e)
}
}

My suggestion for this problem is instead of throwing an error return a Result type in your function. It would be something like this.
enum MyCustomError: Error {
case genericError
}
func operationThatFails() -> Result<Response, MyCustomError> {
guard requiredConsition() else {
return .failure(.genericError)
}
return Response()
}
Then you can handle the error like this:
let result = operationThatFails()
switch result {
case .success(let value):
// handle success
case .failure(let error):
// handle error
}
This way your error is always type safe

Related

Handling errors in swift with try/catch

I come from a .NET background, where error handling can be as simple as wrapping a set of statements in a try-catch. For example:
try
{
statement1
statement2
}
catch (ex)
{
log(ex.Message)
}
I'm trying to add error handling in my Swift project, and all the articles I have read so far seem to indicate that error handling requires more work in Swift. In the example above, it seems I would need to know exactly which statement throws an error, and then add a "try" before it. Is it not possible to simply wrap a block of code in a try-catch, and inspect the error that gets thrown?
Nope, you can't just wrap a block of code with try-catch.
First of all, cause not every line of code could produce exceptions. Only functions marked as "throws" could produce exceptions.
For example, you have some function:
deserialise(json: JSON) -> MyObjectType throws
And let this functions throws exceptions of type MyErrorType
That's how you should use it:
....
do {
let deserialisedObject = try deserialise(jsonObject)
... // do whatever you want with deserialised object here
} catch let error as MyErrorType {
... // do whatever you want with error here
}
...
So, as you see, exceptions in swift is not the same thing as exceptions in C++(or other regular language) for .NET
You can use try catch in swift just like you do in .net with this little change in structure,
before that create a enum of exceptions which you want to catch like follows
//exceptions to catch, change as per your need
enum someActionError: Error {
case invalidSelection
case outOfStock
}
//use
do {
try statement1
} catch someActionError.invalidSelection {
print("Invalid Selection.")
} catch someActionError.outOfStock {
print("Out of Stock.")
}

Do Try Catch.. A whole block of code in Swift 2

Coming from Android, wrapping a block of code in a try..catch statement is straightforward.
try{
//A whole lot of code
} catch (Exception e) {
//Exception is a parameter
}
I wanted to do the same thing in Swift, but it doesn't seem to be quite this easy.
If I understand correctly, you need place a try in front of something that you think will go wrong.
Is there anything similar to the Android - functionality I described in the Swift toolbox?
Error handling in Swift 2 takes two things into consideration:
Whether the method can throw an error (marked with throws keyword in its declaration).
Whether the method that can throw is called from throwing scope (e.g. another methods that can throw) or not.
For non-throwing methods it's simple: you do not need to put any try or do/catch.
Methods that throw must always be prefixed by try, regardless of scope. So, that's a part of the answer to your question.
In case if scope is throwing, you do not have to use do/catch (but you can). In this case all errors thrown in current scope that are not handled by it will be passed upstream to the parent throwing scope.
If the scope is non-throwing, then you must handle all errors that can possibly be thrown by the methods that are called from said scope. Therefore, you must use do/catch.
Depending on your particular case, you might have to put do/catch around as well. If your current scope is non-throwing you will have to.
There are 3 types of do/catch.
I. Catch all
do {
methodThadDoesNotThrow()
try methodThatThrows()
}
catch {
// This will catch all errors that can be possibly thrown.
// You get implicit local-scope variable `error` that holds thrown error.
}
II. Catch concrete error type
Errors that can be thrown must implement ErrorType protocol. This is the only pre-requisite. They do not really have to be NSError or its descendants (this type is just a legacy from Objective-C). Therefore, if you know the concrete error type that you expect you can do something like:
do {
methodThadDoesNotThrow()
try methodThatThrows()
}
catch let error as CustomErrorType {
// This will catch all `CustomErrorType` errors.
// You get explicit local-scope variable `error` of `CustomErrorType` type.
}
III. Catch concrete error instance
Typically error types are declared as enums. For example:
enum CustomErrorType {
case SomethingStrange(String)
case SomethingMildlyHorrible
case Apocalypse
}
If you want to catch some specific case of CustomErrorType, you can do:
do {
methodThadDoesNotThrow()
try methodThatThrows()
}
catch CustomErrorType.SomethingStrange(let message) {
// This will catch only `CustomErrorType.SomethingStrange` errors.
// You get explicit local-scope variable `message` that
// will come from the value associated with the error enum-case.
}
There is, of course, the case of:
IV. Combine all together
do {
methodThadDoesNotThrow()
try methodThatThrows()
}
catch CustomErrorType.SomethingStrange(let message) {
// This will catch `CustomErrorType.SomethingStrange` error.
}
catch let error as CustomErrorType {
// This will catch the rest of `CustomErrorType` errors.
}
catch {
// Finally, this will catch all the rest of the errors
// (anything that is not `CustomErrorType` in this case).
}

How to avoid returning an optional after throwing an exception?

I'm writing a utility function which takes a parameter and always returns a valid non-nil result (notice the returned value is not optional because the possible parameters are all actually hardcoded and valid, so I know the function cannot fail):
func myFunction(param: String) -> NonTrivialObject {...}
Now, during development I want to experiment with possible parameters and, should I make a mistake, I want the function to throw an exception and just crash. I don't want or need to throw Swift errors or catch them, I want to hard-crash and fix the parameter immediately. In Objective C I would just use NSParameterAssert() or do something along these lines:
guard let validatedParam = param where param != nil else {
NSException(...).raise()
return nil
}
// do the actual work and return a non-optional result
However, I cannot return nil because the result is not an optional. Is there a way to somehow tell the compiler that it doesn't need to bother returning anything from the function after an exception is thrown? Or am I doomed to litter my code with unwrapping optionals or try! statements or to return a dummy object just to make the compiler pleased?
You can use Swift assert(_:_file:line:) function as follows
assert(some condition, "Message to display if condition is false (optional)" )
If the condition is verified the app will continue running, otherwise it will terminate
An optional may contain nil, but Swift syntax forces you to safely deal with it using the ? syntax to indicate to the compiler you understand the behavior and will handle it safely.
You can define the function to be a throwing function:
func foo(param: String) throws -> NonTrivialObject {
guard param != nil else {
throw SomeErrorEnum.NilFound
}
doStuff(...)
}
The error enum needs to conform to the ErrorType protocol. The function call is now able to catch errors like this:
do {
try foo(param)
} catch SomeErrorEnum.NilFound {
print("Found nil")
}
In this way the function returns a non-optional but can also throw errors. For more information see: https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ErrorHandling.html

What is the _ underscore in front of Swift's catch block?

Swift 2.0 added do {} catch {} which can be used like so:
do {
let jsonData = try NSJSONSerialization.dataWithJSONObject(params, options: []);
} catch let jsonError as NSError {
print(jsonError);
}
but I've also seen in in my 2.0 converted classes the catch implemented with an underscore:
do {
let jsonData = try NSJSONSerialization.dataWithJSONObject(params, options: []);
} catch _ {
}
what makes it especially confusing is why not just provide nothing after catch which is perfectly valid code:
do {
let jsonData = try NSJSONSerialization.dataWithJSONObject(params, options: []);
} catch {
}
What is that underscore _, what can I do with it, how would I implement that in my own function signatures? In the previous Swift 1.2 declaration I didn't use the NSError so it makes sense that the conversion is throwing the error away but why use _?
You're asking a question about an automatic conversion. It's just a starting place! Apple doesn't know what you want to do, so they provide a completely minimal neutral catch-all catch block — it does nothing at all, but we compile because there's a catch-all. Obviously if you want to capture the error variable, you will delete the _ and capture the error variable. You might want to do much more, e.g. write a more focused catch block. It's up to you to build on the foundation you've been given.
If the variable declared before the catch block isn't actually used in the following block then Xcode will automatically convert this to an _ since it is not used. So in your example above, if jsonError wasn't actually used in the catch block, Xcode may automatically convert this to _. This isn't just for do {} catch {} but also things such as if let ... { }.
I think because it does this convert with other things too, like the if let ... {}, if they were to not put the _ in these places the code wouldn't actually work. Hence it does _ everywhere to be safe, even though in some places you may not actually need it.

How do I handle runtime error in swift?

I do not know how do I handle runtime error in swift. I need to check for a parsing error and do something about it. Can anyone help me please?
I have code something like this:
var:SomeObject = parse("some string")
I need to handle any generic error that occurs in runtime.
Thanks!
If the function is yours, then in case of a failure, you can make that function return a nil value.
That way your line of code
var anObj:SomeObject = parse("some string")
would become something like this
var:SomeObject? = parse("some string")
Notice the ? sign. It means that the value in it is Optional. In simple words, it could be some actual value, or it could be nil.
After this function, you should perform a check like
If anObj != nil
{
//do something
}
else
{
//the parse didn't go right, handle the erorr here.
}
Swift 2 adds additional safety to your error checking. You use the throws keyword to specify which functions and methods could throw an error. Then you have the do, try, and catch keywords for when you call something that could throw:
// 1
enum ParseError: ErrorType {
case InvalidValue
}
// 2
func parseWithError(value:String) throws {
if value.count > 0 {
// yeaaa!
} else {
// 3
throw ParseError.InvalidValue
}
}
func parse(value:String) {
// 4
do {
try parseWithError(value)
} catch {
print("Could not parse! :[")
return
}
}
There are a few things to highlight here:
To create an error to throw, simply create an enum that derives from ErrorType.
You need to use the throws keyword to mark any function that can throw an error.
This throws an error, which will be caught in section 4.
Instead of try blocks, which might be familiar from other languages, you wrap any code that can throw an error in a do block. Then, you add the try keyword to each function call that could throw an error.
For more read here or this is the official documentation of Error Handling