vmartinelli
(Vanderlei Martinelli)
1
Hello all.
Sometimes I have code like this in my apps:
do {
try self.requestSomething()
}
catch RequestError.failed(let statusCode) {
if statusCode == 404 {
self.doSomethingElse()
}
else {
throw RequestError.failed(statusCode)
}
}
What I'd like to write is:
do {
try self.requestSomething()
}
catch RequestError.failed(let statusCode) {
if statusCode == 404 {
self.doSomethingElse()
}
else {
rethrow
}
}
In C# there is the empty throw (wich many programmers forget about and use throw error losing the real exception callstack).
I know that in Swift the context is not the same, but I'm thinking about something like that. A keyword called rethrow (to match the other pair: throws and rethrows) that simply rethrows the error captured in the catch statement.
(If Swift already has equivalent functionally, please enlighten me.)
What do you think?
— Van
2 Likes
Important thing to understand: Swift has NO exceptions. Do catch is only syntactic sugar for the return of a NSError value.
vmartinelli
(Vanderlei Martinelli)
3
Well remembered. That's why I said that the context is not the same. By the way, Swift's solution is very shrewd. 
bzamayo
(Benjamin Mayo)
4
I know this doesn't handle all possible cases where rethrow might be used, but in your given example you can write this in current Swift:
do {
try self.requestSomething()
} catch RequestError.failed(statusCode: 404) {
self.doSomethingElse()
} catch let error {
throw error
}
... which is an incredibly elegant solution to the problem. You can even drop the 'let error' from the final catch statement if you want even more brevity. I find most error-handling situations in my own code can be dealt with in similar ways to this.
2 Likes
vmartinelli
(Vanderlei Martinelli)
5
@bzamayo Good catch! (No pun intended.) I think that in your example the catch let error can be omitted at all, leaving just the catch RequestError.failed(statusCode: 404). Am I right?
1 Like
bzamayo
(Benjamin Mayo)
6
Not quite. The Swift error pattern matching model has a weird quirk where it binds a variable error in the catch all case where you specify no pattern. So this is valid code:
do {
try self.requestSomething()
} catch RequestError.failed(statusCode: 404) {
self.doSomethingElse()
} catch {
throw error
}
Of course, if the outer context is throwing, then yeah — you could omit the final catch too.
Joe_Groff
(Joe Groff)
7
In Swift, you can just throw the error value you caught, perhaps using the implicit error variable binding inside catch blocks:
do {
try something()
} catch {
doMyErrorHandlingStuff()
throw error
}
Unlike C++, there'd be no semantic difference between a rethrow and throwing the same value, so there's no need for rethrow to be a special form.
sharplet
(Adam Sharp)
8
Here's one of my use cases:
init(from decoder: Decoder) throws {
do {
decoded = try decoder.singleValueContainer().decode(T.self)
} catch let error as DecodingError {
switch error {
case .dataCorrupted, .typeMismatch, .valueNotFound:
decoded = nil
case .keyNotFound:
throw error
}
}
}
What I really wanted to write was this:
do {
// stuff
} catch DecodingError.dataCorrupted, DecodingError.typeMismatch, DecodingError.valueNotFound {
decoded = nil
}
But the catch clause's pattern matching abilities don't seem to be as fully featured as switch.
1 Like
Joe_Groff
(Joe Groff)
9
Hm, I can't think of a good reason we wouldn't support multiple patterns in a catch block. That seems worthy of a bug report to me.
4 Likes
sharplet
(Adam Sharp)
10
3 Likes