Better Programming

Advice for programmers.

Follow publication

Beautify Code Without Optionals in Swift

Ash Slone
Better Programming
Published in
3 min readJun 4, 2023

--

Photo by Sven on Unsplash

Optionality, while safe, can provide us with multiple issues that we need to handle and/or compensate for.

I’ll be going through ways of handling optionals within function returns here so that whoever needs to consume it doesn’t have to deal with optionals. They can be applied to other areas, though. I’ll walk you through from bad to good, and at the end, we will see two different ways of handling this that I would consider best practice.

Force Unwrap

Looking at this code here, it’s quite unsafe if the section string passed in isn’t in the Dictionary. When you force unwrap, you’re saying you expect this to not be nil and to be around however, if it is nil, it will crash your application.

Empty Array

This code is a bit better because it is at least safe and won’t crash; however, there isn’t as much context here. We could add an isEmpty check after line 12, and this is totally acceptable but when designing for function returns it’s usually better to return something that gives more info.

The next couple of options/routes are equally as good, depending on your use case.

Throwing Errors

So, a few things are going on in this next example. While this article focuses on function returns, let’s take a moment and look at the Section enum before looking at the throwing of an Error. It’s better to make an enum type for your keys because that locks in what can be keys in Dictionaries instead of String keys where you essentially have unlimited options for keys.

Now, let’s look at this throwing function. When you can, it’s good to throw an Error, particularly a custom error like the SectionError. There are a few reasons why this is better than the force unwrap and the empty array we just saw because throwing an Error gives more context to the issue for whoever might be consuming this. These aspects allow them to correspond appropriately (we will see a more in-depth use case shortly) and on the happy path, it lets the consumer, whoever that might be, deal with actual data.

Result

Now, with the use of Result, the code is basically the same as the previous section, but if the data is there, we return success. If not, a failure. This also allows the consumer to handle the two flows quite easily with a switch/case.

Either way you go, Result or throw, it should be the preferred way of handling your functions. Like always, though, it depends on your specific use case.

With either of these, we can easily handle multiple error cases, as we will see.

Throwing of Multiple Errors

Our function could throw multiple Errors depending on what we want out of it. If we are expecting multiple Errors, we can quite easily handle them in a Do Catch because Catch can act like an if-else-if statements so we can essentially say catch _____ error. Handling Errors like this is easier to read and understand but also allows us to handle these specific cases.

Result Failure Multiple Errors

We can do the same with Result, but the readability suffers here as we need a where clause for each case.

Personally, I would choose to throw an Error over Result, as the readability is much better.

Either way, Result or throw allows for more context and specific error handling. The returning of a blank array if nil works fine, but ideally, we want the consumer of this function to make the call on what to do with it.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Ash Slone
Ash Slone

Written by Ash Slone

Lead Engineer | Polyglot | Living Down Under

Responses (2)

Write a response