Returning Error vs Throwing Error in Swift

Which one to use? It depends…

Jimmy Liu
4 min readOct 10, 2019

In Swift, there are two Error Handling Patterns, including:

  • Return Value — the function simply returns the value of interest, it can be Boolean, Class, Enum and other types.
  • do-catch statement — the function will throw errors. These errors are then caught by do-catch statement. Here is the general form of this statement:
do {
try functionThatThrowsError()
} catch ERROR_TYPE {
//Implementation
}

So what are the differences?

In order to get to answer this question, let me show you an example.

Let’s say we have a Car, and we need to decide whether it has enough fuel and if the engine is overheated. These will be determined by two functions, driving() and temperatureChanged(_:Double). Let’s start by examining the return value pattern.

Returning Values

First, we will define an enum for temperature, EngineTemperature. This allows us to have clearer return values.

Next, I will implement a struct called Car.

In Car the two main functions:

  • driving() → Bool will return False when gas is not enough.
  • temperatureChange(_:Double) → EngineTemperature will return TooHigh when temperature is ≥ 100, ABitHot when the temperature is 100 ≥ t ≥ 60 and Cool when temperature is < 60.

Here is how we can create a Car type and see whether we have enough gas.

As you can see, the return value pattern is very straight forward. However, there are chances that you might ignore some errors when implementing it. Also, this implementation requires a lots of conditional statements, and this could reduce the readability of the code.

Next, let’s see how we implement it with do-catch statement.

Do-Catch Statement

First, we need to define two enums called EnginError and EngineTemperatureError that adapts the Error Protocol, a type representing an error value that can be thrown.:

EngineError has an error called InsufficientGas, and EngineTemperatureError has two errors with associated values, EngineTooHot and EngineABitHot.

Next, here is the implementation of struct Car:

Since we will be throwing errors, we don’t need to return any values from driving() and temperatureChange(_: Double).

And here is how we call them:

With this pattern, we can clearly separate the code for regular implementation and code that handles errors. Even though throwing errors makes the code clearer and more readable, but it does add some complexity to the code.

Also, do-catch statement seems to be a bit overkill to be used to determine whether the car can still drive, a simple Bool is good enough.

Finally, let’s take a look at their pros and cons.

Pros and Cons

Return Value

  • Pros: Easy to implement.
  • Cons: Not suited when you need more info about the returning value.

Do-Catch Statement

  • Pros: Allows you to have a more complex error structure using associate values. Increase the readability of your code.
  • Cons: Complexity. Overkill if you want to return a simple value.

In our example, if we simply want to know if we have enough fuel to keep driving, then returning a Bool is good enough. However, when we want to know the temperature of the engine, and see if it is overheated or just mildly heated, then throwing an error would be more suited.

Summary

You should see what the purpose of the function is and what you are trying to accomplish.

If you wish to get some simple values from a function, use Return Value Pattern.

If you wish to get more than a simple value, perhaps the meaning of the value, then Do-Catch / Throw Error Pattern is more suitable.

Reference :

Swift 3 Protocol-Orientated Programming

Thanks for reading!

--

--

Jimmy Liu

App Developer who enjoy learning from the ground up.