released Thu, 20 Aug 2015
Swift Version 5.1


Best practices for handling Swift's Optional and extending them to make them much more approachable

What are Optionals

Optionals are one of the staple features of Swift. They're something that appears very, very often during normal iOS development. Much more often than other features such as enums or generics.

However, if you're new to Swift and come from a different programming language such as Python, Ruby, or even Objective-C, then optionals can be daunting. This guide is split up into a basic introduction into Optionals for those new to the subject matter and an advanced guide that will showcase more advanced optional handling for more seasoned developers.

Lets begin by briefly explaining why optionals are even needed.

Why Optionals are useful

Optionals aim to solve a problem related to something called "null pointers". We don't want to go too much into the history here, instead, we will showcase a typical situation where optionals are needed.

Imagine that you write your own User Defaults. We want to store a value String for a key String . We will ignore almost everything except for the one function get that allows us to get a String from the defaults.

struct MyDefaults {


   /// A function that returns a `String`

   func get(key: String) -> String {



The problem is what do we do when we don't have that value in our defaults? What would we return? Now, we could return an "Empty" string, but that wouldn't be right, would it? Imagine you'd save the username in the defaults. Next time the user starts his app he'd see an empty username.

What you really want to do is express the notifion of "Nothing". We kinda want to write something like the following:

func get(key: String) -> String or Nothing {


This either gives us back a string or it gives us back nothing. This is fundamentally what optionals are good for. They explain to the Swift type system and to the user that a value can either be Something or Nothing. The implementation is also really simple. It is just an enum with two cases: some and none. Some, has the actual value. Here's a simplified version:

enum MyOptional {

   case some(String)

   case none


That's it. Now, the actual Swift Optional is not limited to Strings, instead it uses generics in order to provide support for any kind of type. It kinda looks like this:

enum Optional<Wrapped>

   case some(Wrapped)

   case none

So what do we do if we call a function that returns an optional? Since optionals are just simple enums, we can just use Swift's normal enum handling for this:

let optionalValue = functionReturningOptional()

switch optionalValue {

case .some(value): print(value)

case .none: print(\"Nothing\")


The types of Optionals

Thankfully, we don't have to spell out the long Optional.some all the time. Instead, Swift offers us a very brief alternative, which is just adding a questionmark ? to a type. This will tell Swift that this type is an Optional. This means that the following two are equal:

let one: Optional<Int> = Optional.some(5)

let two: Int? = 5

This is usually the default Syntax for Optionals in Swift. You'll hardly see the other Syntax, but it is still good to know as you might stumble upon it from time to time.

Also, if you want to create an empty optional, you can just use nil as a shorthand for the empty optional. Again, the following two lines are equal:

let one: Int? = Optional.none

let two: Int? = nil

You can only use nil if Swift can somehow infer the type of the Optional, so the next example does not work because Swift does not know what kind of Optional this is. Is this a Int? or a Float? or a String?. Swift can't find out:

let doesNotWork = nil

Swift offers many ways of handling Optional types. Lets look at them next.

How to handle optionals

As we saw in the previous chapter, Optionals are really just enum types. However, as they're deeply ingrained into the language, Swift offers a lot of additional possibilities of handling Optionals.

If Let

Certainly the most used one is the so-called if let. You're basically telling Swift "If this optional value myOptionalValue actually contains a value, please give me the contained value into the variable named myUnwrappedValue":

if let myUnwrappedValue = myOptionalValue {



If myOptionalValue is actually empty, then the print statement would never be executed. As with any typical if statement, this can also have an else expression:

if let myUnwrappedValue = myOptionalValue {


} else {

   print(\"No Value\")


You can also combine multiple if let statements if you need to handle multiple Optional values:

if let firstValue = firstOptionalValue,

    let secondValue = secondOptionalValue,

    let thirdValue = thirdOptionalValue {

    print(firstValue, secondValue, thirdValue)


Finally, you can mix and match the if let pattern with normal if expressions:

if let firstValue = firstOptionalValue,

    firstValue > 10

    let secondValue = secondOptionalValue,

    secondValue == \"HTTP\",

    let thirdValue = thirdOptionalValue {

    print(firstValue, secondValue, thirdValue)


In this example, we only print the three values if the firstOptionalValue is not empty and has a value > 10, and if the second optional value is not empty and has the value "HTTP" and if the third optional value is not empty.


Another nice feature of Swift are the guard statements. They're basically like inverted if statements. You usually use them at the beginning of a block of code to make sure that all your requirements are held. The main difference compared to if let is that you're required to leave the current scope (i.e. return, continue, or break) if the guard does not succeed. Lets look at this nonsensical function that tries to do addition with two Optional Int values. For that to work, we need to make sure that

func addOptionals(firstNumber: Int?, secondNumber: Int?) -> Int? {

   guard let first = firstNumber, let second = secondNumber

         else { return nil }

   return first + second


So here, we do the guard let in order to make sure that both firstNumber and secondNumber have a value, otherwise we can't really do the addition. So if one of them (or both) don't have a value, we return early in the else { return nil} block.

Observe how with if let the code-to-be-executed is within the if braces, while with guard let it is not:

if let a = b {



guard let a = b else { return }


This makes it easier to follow the structure of code because your main code is not nested but only at the very left side of the function.


We already mentioned this in the previous chapter, but you can also use switch to handle Optionals:

switch myOptionalValue {

case let value?: print(value)

default: ()


We have a whole guide on pattern matching with Swift where this is explained in much more detail.

Forced Unwrap

Sometimes, if you're absolutely sure that your Optional has a value, you can also use the forced unwrap. This tells Swift to handle this Optional value as if it was a non-optional value.

This works great, but it means that the optional has to have a value. If you try a forced unwrap on an empty optional (i.e. nil) it will cause a runtime error (meaning, crash).

let oneValue: Int? = 5

let twoValue: Int? = nil

print(oneValue!) // No Crash

print(twoValue!) // Crash

But wait, there's more. The next section in our guides discusses two additional methods of handling optionals that are also really, really useful: Optional Chaining and Map.

Advanced Optionals

We've already seen the basics of handling optionals. However, there's much more you can do. In this section we'll explore optionals even more and have a look at some advanced ways of handling optionals

Optional Chaining

Now imagine your work on a relationship database, and your data are users and their relations. So you'd have a Person and then the person could have an optional child and the child could have an optional sibling and that sibling could have an optional child, and so on.

Since all of these are Person types, we could model the type like this:

struct Person {

   var child: Person?

   var sibling: Person?

   var father: Person?

   var mother: Person?


All of our properties are optional because they can all be nil. Now imagine you'd like to find the following relative:

person -> child -> sibling -> child -> mother

So, how would we do that with if let in Swift? Let us have a try:

if let child = person.child,

    let sibling = person.sibling,

    let nextChild = person.child,

    let mother = nextChild.mother {



This is a lot of code and can quickly become confusing. Thankfully, Swift has another feature which lets us write this in a much simpler fashion.

The idea being that in a chain of operations on optionals (such as Optional.child -> Optional.silbing -> Optional.child) if any of these operations returns nil, we stop executing the chain early.

You represent this behaviour via a ? before calling a method. Here is the previous example implemented with the optional chaining:

if let mother = person.child?.sibling?.child?.mother {



We're basically telling Swift "If the value of the child property of person is not optional, then please get me the sibling property from it". And we do the same again for the next propery.

This, also, works great for dictionaries where all return values are always optional.


By adding ? in between each call / access, Swift will automatically unwrap if there is a value, or stop the chain as soon as any one evaluates to nil.


Consider the following code:

func example() -> Int? {return 10}

if let value = example() {

     storeInDatabase(value * 2)

If we break down the logic, what we\'re really trying to achieve,
were it not for optionals, is the following:

``` Swift
storeInDatabase(example() * 10)

Optionals are still very useful here, as they prevent us from the
danger of multiplying nil with 10 and trying to store that in the
database. But still, we have to admit that the optionals code looks
more convoluted. As you can imagine, there\'s a solution to this, of

Optionals offer an implementation of the `map` function which will
call the value of an optional with a supplied closure if
the optional has a value.
let px: Int? = 5

// This will print \"5\" { print($0) }

// This will do nothing

let px: Int? = nil { print($0) }

This lets us rewrite our example from above in terms of map as follows:

example().map({ number in 

   storeInDatabase(number * 2) 


What happens here is: When the return value of example() is not optional, then the closure will be called the value as number and so we can call the storeInDatabase function with our number multiplied by two. If the return value of example() is empty, nothing will happen.

With Swift's nice simplified closure syntax we can even simply this example to the following:

example().map { storeInDatabase($0 * 2) }

Optionals are a staple of Swift. I guess everybody will agree that they are a huge boon insofar as they force us to properly handle edge cases. The Optional language feature alone removes a whole category of bugs from the development process.

However, the API surface of Swift's optional is rather limited. The Swift documentation lists just a couple of methods / properties on Optional - if we ignore customMirror and debugDescription:

var unsafelyUnwrapped: Wrapped { get } 

func map<U>(_ transform: (Wrapped) throws -> U) rethrows -> U? 

func flatMap<U>(_ transform: (Wrapped) throws -> U?) rethrows -> U? 

The reason why optionals are still very useful even though they have such a small amount of methods is that the Swift syntax makes up for it via features such as optional chaining, pattern matching, if let or guard let. In some situations, though, this manifests itself in unnecessary line noise. Sometimes, a very succinct method will let you express a concept in one short line of code instead of multiple lines of combined if let statements.

I've sifted through Swift Projects on Github as well as the optional implementations of other languages such as Rust, Scala, or C# in order to find a couple of useful additions to Optional. Below are 14 useful Optional extensions. I'll describe them by category and then give a couple of examples per category. Finally, I'll write a more involved example that uses several extensions at once.


extension Optional {

     /// Returns true if the optional is empty

     var isNone: Bool {

         return self == .none


     /// Returns true if the optional is not empty

     var isSome: Bool {

         return self != .none



Those are the most basic additions to the optional type. The implementation could also use a switch pattern match instead, but the nil comparison is much shorter. What I like about these additions is that they move the concept of an empty optional being nil away from your code. This might just as well be an implementation detail. Using optional.isSome feels much cleaner and less noisy than if optional == nil:

// Compare

guard leftButton != nil, rightButton != nil else { fatalError(\"Missing Interface Builder connections\") }

// With

guard leftButton.isSome, rightButton.isSome else { fatalError(\"Missing Interface Builder connections\") }


extension Optional {

     /// Return the value of the Optional or the `default` parameter

     /// - param: The value to return if the optional is empty

     func or(_ default: Wrapped) -> Wrapped {

         return self ?? `default`


     /// Returns the unwrapped value of the optional *or*

     /// the result of an expression `else`

     /// I.e. optional.or(else: print(\"Arrr\"))

     func or(else: @autoclosure () -> Wrapped) -> Wrapped {

         return self ?? `else`()


     /// Returns the unwrapped value of the optional *or*

     /// the result of calling the closure `else`

     /// I.e. optional.or(else: { 

     /// ... do a lot of stuff

     /// })

     func or(else: () -> Wrapped) -> Wrapped {

         return self ?? `else`()


     /// Returns the unwrapped contents of the optional if it is not empty

     /// If it is empty, throws exception `throw`

     func or(throw exception: Error) throws -> Wrapped {

         guard let unwrapped = self else { throw exception }

         return unwrapped



extension Optional where Wrapped == Error {

     /// Only perform `else` if the optional has a non-empty error value

     func or(_ else: (Error) -> Void) {

         guard let error = self else { return }




Another abstraction on the isNone / isSome concept is being able to specify instructions to be performed when the invariant doesn't hold. This saves us from having to write out if or guard branches and instead codifies the logic into a simple-to-understand method.

This concept is so useful, that it is defined in three distinct functions.

Default Value

The first one returns the wrapped value of the optional or a default value:

let optional: Int? = nil

print(optional.or(10)) // Prints 10

Default Closure

The second one is very similar to the first one, however it allows to return a default value from a closure instead.

let optional: Int? = nil

optional.or(else: secretValue * 32) 

Since this uses the @autoclosure parameter we could actually use just the second or implementation. Then, using a just a default value would automatically be converted into a closure returning the value. However, I prefer having two separate implementations as that allows users to also write closures with more complex logic.

let cachedUserCount: Int? = nil


return cachedUserCount.or(else: {

    let db = database()


    guard db.failures.isEmpty else { return 0 }

    return db.amountOfUsers


A really nice use case for or is code where you only want to set a value on an optional if it is empty:

if databaseController == nil {

   databaseController = DatabaseController(config: config)


This can be replaced with the much nicer:

databaseController = databaseController.or(DatabaseController(config: config)

Throw an error

This is a very useful addition as it allows to merge the chasm between Optionals and Error Handling in Swift. Depending on the code that you're using, a method or function may express invalid behaviour by returning an empty optional (imagine accessing a non-existing key in a Dictionary) or by throwing an Error. Combining these two oftentimes leads to a lot of unnecessary line noise:

func buildCar() throws -> Car {

   let tires = try machine1.createTires()

   let windows = try machine2.createWindows()

   guard let motor = externalMachine.deliverMotor() else {

     throw MachineError.motor


   let trunk = try machine3.createTrunk()

   if let car = manufacturer.buildCar(tires, windows,  motor, trunk) {

     return car

   } else {

     throw MachineError.manufacturer



In this example, we're building a car by combining internal and external code. The external code (external_machine and manufacturer) choose to use optionals instead of error handling. This makes the code unnecessary complicated. Our or(throw:) function makes this much more readable:

func build_car() throws -> Car {

   let tires = try machine1.createTires()

   let windows = try machine2.createWindows()

   let motor = try externalMachine.deliverMotor().or(throw: MachineError.motor)

   let trunk = try machine3.createTrunk()

   return try manufacturer.buildCar(tires, windows,  motor, trunk).or(throw: MachineError.manufacturer)


Handling Errors

The code from the Throw an error section above becomes even more useful when you include the following free function that was proposed by Stijn Willems on Github. Thanks for the suggestion!

func should(_ do: () throws -> Void) -> Error? {

     do {

         try `do`()

         return nil

     } catch let error {

         return error



This free function (alternatively, you could make it a class method on optional) will perform a do {} catch {} block and return an error if and only if the closure `do` resulted in an error. Take, the following Swift code as an example:

do {

   try throwingFunction()

} catch let error {



This is one of the basic tennets of error handling in Swift, and it introduces quite a lot of line noise. With the free function above, you can reduce it to this simple on-liner:

should { try throwingFunction) }.or(print($0))

I feel that there're many situations where such a one-liner for error handling would be very beneficient.


As we saw above, map and flatMap are the only methods that Swift offers on Optionals. However, even those can be improved a bit to be more versatile in many situations. There're two additional variations on map that allow defining a default value similar to how the or variants above are implemented:

extension Optional {

     /// Maps the output *or* returns the default value if the optional is nil

     /// - parameter fn: The function to map over the value

     /// - parameter or: The value to use if the optional is empty

     func map<T>(_ fn: (Wrapped) throws -> T, default: T) rethrows -> T {

         return try map(fn) ?? `default`


     /// Maps the output *or* returns the result of calling `else`

     /// - parameter fn: The function to map over the value

     /// - parameter else: The function to call if the optional is empty

     func map<T>(_ fn: (Wrapped) throws -> T, else: () throws -> T) rethrows -> T {

         return try map(fn) ?? `else`()



The first one will allow you to map the contents of an optional to a new type T. If the optional is empty, you can define a default value that should be used instead:

let optional1: String? = \"appventure\"

let optional2: String? = nil

// Without

print({ $0.count }) ?? 0)

print({ $0.count }) ?? 0)

// With 

print({ $0.count }, default: 0)) // prints 10

print({ $0.count }, default: 0)) // prints 0

The changes are minimal, but we're moving away from having to use the ?? operator and can instead express the operation more clearly with the default keyword.

The second variant is very similar. The main difference is that it accepts (again) a closure returning value T instead of value T. Here's a brief example:

let optional: String? = nil

print({ $0.count }, else: { \"default\".count })

Combining Optionals

This category contains four functions that allow you to define relations between multiple optionals.

extension Optional {

     /// Tries to unwrap `self` and if that succeeds continues to unwrap the parameter `optional`

     /// and returns the result of that.

     func and<B>(_ optional: B?) -> B? {

         guard self != nil else { return nil }

         return optional


     /// Executes a closure with the unwrapped result of an optional.

     /// This allows chaining optionals together.

     func and<T>(then: (Wrapped) throws -> T?) rethrows -> T? {

         guard let unwrapped = self else { return nil }

         return try then(unwrapped)


     /// Zips the content of this optional with the content of another

     /// optional `other` only if both optionals are not empty

     func zip2<A>(with other: Optional<A>) -> (Wrapped, A)? {

         guard let first = self, let second = other else { return nil }

         return (first, second)


     /// Zips the content of this optional with the content of another

     /// optional `other` only if both optionals are not empty

     func zip3<A, B>(with other: Optional<A>, another: Optional<B>) -> (Wrapped, A, B)? {

         guard let first = self,

               let second = other,

               let third = another else { return nil }

         return (first, second, third)



These four functions all share that they take an additional optional as a parameter and return another optional value. However, they're all quite different in what they achieve.


and<B>(_ optional) is useful if the unpacking of an optional is only required as a invariant for unpacking another optional:

// Compare

if user != nil, let account = userAccount() ...

// With

if let account = user.and(userAccount()) ...

In the example above, we're not interested in the unwrapped contents of the user optional. We just need to make sure that there is a valid user before we call the userAccount function. While this relationship is kinda codified in the user != nil line, I personally feel that the and makes it more clear.


and<T>(then:) is another very useful function. It allows to chain optionals together so that the output of unpacking optional A becomes the input of producing optional B. Lets start with a simple example:

protocol UserDatabase {

   func current() -> User?

   func spouse(of user: User) -> User?

   func father(of user: User) -> User?

   func childrenCount(of user: User) -> Int


let database: UserDatabase = ...

// Imagine we want to know the children of the following relationship:

// Man -> Spouse -> Father -> Father -> Spouse -> children

// Without

let childrenCount: Int

if let user = database.current(), 

    let father1 = database.father(user),

    let father2 = database.father(father1),

    let spouse = database.spouse(father2),

    let children = database.childrenCount(father2) {

   childrenCount = children

} else {

   childrenCount = 0


// With

let children = database.current().and(then: { database.spouse($0) })

      .and(then: { database.father($0) })

      .and(then: { database.spouse($0) })

      .and(then: { database.childrenCount($0) })


There're a lot of improvements when using the version with and(then). First of all, you don't have to come up with superfluous temporary variable names (user, father1, father2, spouse, children). Second, we clearly have less code. Also, using the or(0) instead of a complicated let childrenCount is so much easier to read.

Finally, the original Swift example can easily lead to logic errors. You may not have noticed, but there's a bug in the example. When writing lines like that, copy paste errors can easily be introduced. Do you see the error?

Yeah, the children property should be created by calling database.childrenCount(spouse) but I wrote database.childrenCount(father2) instead. It is difficult to spot errors like that. The and(then:) example makes it much easier because it always relies on the same variable name $0.


This is another variation on an existing Swift concept. The zip method on optional will allow us to combine multiple optionals and unwrap them together or not at all. I've just provided implementations for zip2 and zip3 but nothing prevents you from going up to zip22 (Well, maybe sanity and compiler speed).

// Lets start again with a normal Swift example

func buildProduct() -> Product? {

   if let var1 = machine1.makeSomething(),

     let var2 = machine2.makeAnotherThing(),

     let var3 = machine3.createThing() {

     return finalMachine.produce(var1, var2, var3)

   } else {

     return nil



// The alternative using our extensions

func buildProduct() -> Product? {

   return machine1.makeSomething()

      .zip3(machine2.makeAnotherThing(), machine3.createThing())

      .map { finalMachine.produce($0.1, $0.2, $0.3) }


Less code, clearer code, more beautiful code. However, as a downside, this code is also more involved. The reader has to know and understand zip in order to easily grasp it.


extension Optional {

     /// Executes the closure `some` if and only if the optional has a value

     func on(some: () throws -> Void) rethrows {

         if self != nil { try some() }


     /// Executes the closure `none` if and only if the optional has no value

     func on(none: () throws -> Void) rethrows {

         if self == nil { try none() }



These two short methods will allow you to perform side effects if an optional is empty or not. In contrast to the already discussed methods, these ignore the contents of the optional. So on(some:) will only execute the closure some if the optional is not empty but the closure some will not get the unwrapped contents of the optional.

/// Logout if there is no user anymore

self.user.on(none: { AppCoordinator.shared.logout() })

/// self.user is not empty when we are connected to the network

self.user.on(some: { AppCoordinator.shared.unlock() })


extension Optional {

     /// Returns the unwrapped value of the optional only if

     /// - The optional has a value

     /// - The value satisfies the predicate `predicate`

     func filter(_ predicate: (Wrapped) -> Bool) -> Wrapped? {

         guard let unwrapped = self,

             predicate(unwrapped) else { return nil }

         return self


     /// Returns the wrapped value or crashes with `fatalError(message)`

     func expect(_ message: String) -> Wrapped {

         guard let value = self else { fatalError(message) }

         return value




This is a simple method which works like an additional guard to only unwrap the optional if it satisfies a predictate. Here's an example. Imagine we want to upgrade all our old users to a premium account for sticking with us for a long time:

// Only affect old users with id < 1000

// Normal Swift

if let aUser = user, < 1000 { aUser.upgradeToPremium() }

// Using `filter`

user.filter({ $ < 1000 })?.upgradeToPremium()

Here, user.filter feels like a much more natural implementation. Also, it only implements what already exists for Swift's collections.


This is one of my favorites. Also, I shamelessly stole it from Rust. I'm trying very hard to never force unwrap anything in my codebase. Similar for implicitly unwrapped optionals.

However, this is tricky when working with interface builder outlets. A common pattern that I observed can be seen in the following function:

func updateLabel() {

   guard let label = valueLabel else {

     fatalError(\"valueLabel not connected in IB\")


   label.text = state.title


The alternative solution, obviously, would be to just to force unwrap the label, as that leads to a crash just like fatalError. Then, I'd have to insert ! though, also it wouldn't give me a nice succinct description of what actually is wrong. The better alternative here is to use expect as implemented above:

func updateLabel() {

   valueLabel.expect(\"valueLabel not connected in IB\").text = state.title



So now that we've seen a couple of (hopefully) useful Optional extensions, I'll set up an example to better see how some of these extensions can be combined to simplify optional handling. First, we need a bit of context. Forgive me for the rather unconventional and impossible example:

You're working in the 80s at a shareware distributor. A lot of student programmers are working for you and writing new shareware apps and games every month. You need to keep track of how many were sold. For that, you recieve an XML file from accounting and you need to parse it and insert it into the database (isn't it awesome how in this version of the 80s there's Swift to love but also XML to hate?). Your software system has an XML parser and a database (both written in 6502 ASM of course) that implement the following protocols:

protocol XMLImportNode {

     func firstChild(with tag: String) -> XMLImportNode?

     func children(with tag: String) -> [XMLImportNode]

     func attribute(with name: String) -> String?


typealias DatabaseUser = String

typealias DatabaseSoftware = String

protocol Database {

     func user(for id: String) throws -> DatabaseUser

     func software(for id: String) throws -> DatabaseSoftware

     func insertSoftware(user: DatabaseUser, name: String, id: String, type: String, amount: Int) throws

     func updateSoftware(software: DatabaseSoftware, amount: Int) throws


A typical file looks like this (behold the almighty XML):

 <user name="" id="158">
   <package type="game" name="Maniac Mansion" id="4332" amount="30" />
   <package type="game" name="Doom" id="1337" amount="50" />
   <package type="game" name="Warcraft 2" id="1000" amount="10" />

Our original Swift code to parse the XML looks like this:

enum ParseError: Error {

     case msg(String)


func parseGamesFromXML(from root: XMLImportNode, into database: Database) throws {

     guard let users = root.firstChild(with: \"users\")?.children(with: \"user\") else {

         throw ParseError.msg(\"No Users\")


     for user in users {

         guard let software = user.firstChild(with: \"software\")?

                 .children(with: \"package\"),

             let userId = user.attribute(with: \"id\"),

             let dbUser = try? database.user(for: userId)

             else { throw ParseError.msg(\"Invalid User\") }

         for package in software {

             guard let type = package.attribute(with: \"type\"),

             type == \"game\",

             let name = package.attribute(with: \"name\"),

             let softwareId = package.attribute(with: \"id\"),

             let amountString = package.attribute(with: \"amount\")

             else { throw ParseError.msg(\"Invalid Package\") }

             if let existing = try? softwareId) {

                 try database.updateSoftware(software: existing, 

                                               amount: Int(amountString) ?? 0)

             } else {

                 try database.insertSoftware(user: dbUser, name: name, 

                                               id: softwareId, 

                                             type: type, 

                                           amount: Int(amountString) ?? 0)





Lets apply what we learned above:

func parseGamesFromXML(from root: XMLImportNode, into database: Database) throws {

     for user in try root.firstChild(with: \"users\")

                     .or(throw: ParseError.msg(\"No Users\")).children(with: \"user\") {

         let dbUser = try user.attribute(with: \"id\")

                     .and(then: { try? database.user(for: $0) })

                     .or(throw: ParseError.msg(\"Invalid User\"))

         for package in (user.firstChild(with: \"software\")?

                     .children(with: \"package\")).or([]) {

             guard (package.attribute(with: \"type\")).filter({ $0 == \"game\" }).isSome

                 else { continue }

             try package.attribute(with: \"name\")

                 .zip3(with: package.attribute(with: \"id\"), 

                    another: package.attribute(with: \"amount\"))

                 .map({ (tuple) -> Void in

                     switch try? tuple.1) {

                     case let e?: try database.updateSoftware(software: e, 

                                                                amount: Int(tuple.2).or(0))

                     default: try database.insertSoftware(user: dbUser, name: tuple.0, 

                                                            id: tuple.1, type: \"game\", 

                                                        amount: Int(tuple.2).or(0))


                 }, or: { throw ParseError.msg(\"Invalid Package\") })




If we look at this, then there're two things that immediately come to mind:

  1. Less Code
  2. More Complicated Looking Code

I deliberately went into overdrive when utilizing the various Optional extensions. Some of them fit better while others seem to be a bit misplaced. However, the key is not to solely rely on these extensions (like I did above) when using optionals but instead to mix and match where it makes most sense. Compare the two implementations and consider which from the second example you'd rather implement with Swift's native features and which feel better when using the Optional extensions.

Similar Articles