
Error handling in Swift
Swift is a relatively young language with every single version bringing new concepts. Swift 2.0, for example, came up with a brand new (well, maybe not that new, some languages have had similar features for over 20 years) mechanism for error handling. It was a huge thing since we had already had very nice and safe language up to this point, but we still needed to pass errors in method arguments. So it was no surprise when Apple announced a new way of doing that. They decided to add do-try-catch
blocks and convince developers that this is the right way of handling errors in their apps. Let’s take a look at some commonly used code for converting NSData
to JSON dictionary. In Swift 1 we would write it like this:
Now, we write it like this:
Is it better? Maybe a bit, but it’s still a lot of code to write only for checking if data was parsed successfully. Secondly, for a few minutes imagine that you haven’t seen JSONSerialization
class before and this code is totally unfamiliar to you. Can you tell me what type of errors can you expect here? No, you can’t, you don’t have any information what type of error function can throw. You have to dig into class implementation to find it. And last but not least, what about asynchronous code? Are do-try-catch
blocks helpful when you handle network errors? Nope. You need to wrap it, hack it and then you still finish with an old success-failure pair of callbacks.
Meanwhile in Optional
world
Of course, I’m not the only person who dislikes the mechanism introduced by Apple. Many developers tried to find a better solution for error handling. Some of them looked at our beautiful optionals (well, not that beautiful for everyone, but still) and thought about how we can use a similar idea to handle errors. And they found the solution – Result
type was born and everybody was happy.
Or were they?
Result
type is an awesome concept, which works in every case, keeps strong typing and provides information about a type of errors. There’s only one drawback… This is the most popular implementation of Result
type:
Let’s try to write a code for converting Data
to JSON dictionary which potentially would use Result
type:
Wait… It’s as long as before… And even more verbose… And you need to write this ugly switch
statement every time you handle error. So yes, it does have some big advantages over try-catch
ing, but it’s very inconvenient to write. Ughh…
Dreams…
One evening, I was wondering how the ideal error handling in Swift would look like. After a few minutes I came to conclusion that I still like Result
approach, the only thing it needs is a better syntax. In my opinion the best solution would look something like if let
syntax for optionals, but with additional error
variable:
Looks awesome, doesn’t it? Unfortunately, we can’t have it in Swift. However…
… come true (almost)
When Swift was announced in 2014, Apple emphasized how flexible their new language is. With that in mind, I decided to try to hack our favourite language a bit. Of course, if let
syntax is untouchable and we can’t do anything with it, but we have many other tools like closures, trailing closure syntax or enum methods. Using this three tools, I added a few lines of code to our Result
enum:
What does it look now? Let’s find out:
Well, it looks much better than switches and try-catch
blocks, right? And the most important thing: we still keep type safety and information about returned errors.
Conclusions
I spent about an evening on writing this code and half an hour discussing it with my colleagues. I don’t know if it’s a good solution. I don’t even know if it’s good enough to use it in a production code. But I like this approach, it’s natural extension of Optional
concept and I’m going to try it out in my projects.
I’m very curious about your opinion on this approach. Since we don’t have comments on our blog (yet! :P), I’d recommend you to visit our Facebook page, where we can discuss this topic and maybe find even better solutions.