Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are the differences between throws and rethrows in Swift?

After searching for some references to figure it out, -unfortunately- I could not find useful -and simple- description about understanding the differences between throws and rethrows. It is kind of confusing when try to understand how we should use them.

I would mention that I am kind of familiar with the -default- throws with its simplest form for propagating an error, as follows:

enum CustomError: Error {     case potato     case tomato }  func throwCustomError(_ string: String) throws {     if string.lowercased().trimmingCharacters(in: .whitespaces) == "potato" {         throw CustomError.potato     }      if string.lowercased().trimmingCharacters(in: .whitespaces) == "tomato" {         throw CustomError.tomato     } }  do {     try throwCustomError("potato") } catch let error as CustomError {     switch error {     case .potato:         print("potatos catched") // potatos catched     case .tomato:         print("tomato catched")     } } 

So far so good, but the problem arises when:

func throwCustomError(function:(String) throws -> ()) throws {     try function("throws string") }  func rethrowCustomError(function:(String) throws -> ()) rethrows {     try function("rethrows string") }  rethrowCustomError { string in     print(string) // rethrows string }  try throwCustomError { string in     print(string) // throws string } 

what I know so far is when calling a function that throws it has to be handled by a try, unlike the rethrows. So what?! What is logic that we should follow when deciding to use throws or rethrows?

like image 583
Ahmad F Avatar asked Apr 09 '17 09:04

Ahmad F


People also ask

What is difference between throw and throws in Swift?

To indicate that a function, method, or initializer can throw an error, you write the throws keyword in the function's declaration after its parameters. A function marked with throws is called a throwing function. If the function specifies a return type, you write the throws keyword before the return arrow ( -> ).

When to use rethrows Swift?

The rethrows keyword is used in functions that do not throw errors themselves but instead forward errors from their function parameters. It also allows the compiler to ask for the try keyword only if the given callback actually is throwing errors.

What does throws mean in Swift?

Swift version: 5.6. Throwing functions are those that will flag up errors if problems happen, and Swift requires you to handle those errors in your code. To make a throwing function, just write throws before your function's return value.


1 Answers

From "Declarations" in the Swift book:

Rethrowing Functions and Methods

A function or method can be declared with the rethrows keyword to indicate that it throws an error only if one of it’s function parameters throws an error. These functions and methods are known as rethrowing functions and rethrowing methods. Rethrowing functions and methods must have at least one throwing function parameter.

A typical example is the map method:

public func map<T>(_ transform: (Element) throws -> T) rethrows -> [T] 

If map is called with a non-throwing transform, it does not throw an error itself and can be called without try:

// Example 1:  let a = [1, 2, 3]  func f1(n: Int) -> Int {     return n * n }  let a1 = a.map(f1) 

But if map is called with a throwing closure then itself can throw and must be called with try:

// Example 2:  let a = [1, 2, 3] enum CustomError: Error {     case illegalArgument }  func f2(n: Int) throws -> Int {     guard n >= 0 else {         throw CustomError.illegalArgument     }     return n*n }   do {     let a2 = try a.map(f2) } catch {     // ... } 
  • If map were declared as throws instead of rethrows then you would have to call it with try even in example 1, which is "inconvenient" and bloats the code unnecessary.
  • If map were declared without throws/rethrows then you could not call it with a throwing closure as in example 2.

The same is true for other methods from the Swift Standard Library which take function parameters: filter(), index(where:), forEach() and many many more.

In your case,

func throwCustomError(function:(String) throws -> ()) throws 

denotes a function which can throw an error, even if called with a non-throwing argument, whereas

func rethrowCustomError(function:(String) throws -> ()) rethrows 

denotes a function which throws an error only if called with a throwing argument.

Roughly speaking, rethrows is for functions which do not throw errors "on their own", but only "forward" errors from their function parameters.

like image 136
Martin R Avatar answered Oct 06 '22 00:10

Martin R