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.
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
Let’s try to write a code for converting
Data to JSON dictionary which potentially would use
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-catching, but it’s very inconvenient to write. Ughh…
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
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
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.
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.
Also published on Medium.