Storing two types in the same variable using Either


You’re more of a video kind of person? I’ve got you covered! Here’s a video with the same content than this article 🍿


I want to show you a really nice trick for when you need to refactor code to deal with heterogeneous pieces of data.

Let’s take a look at this code: we’ve implemented a SwiftUI view that displays a List of movies.

But now let’s imagine that we’re given a new requirement: we want to monetize our app, so we’ll also be displaying a few ads in between the movies.

So the question is: what’s the simplest way to update our code so that it satisfies the new requirement and that it also stays easy to maintain?

A great solution is to use a generic type called Either.

The type Either is a generic enum that declares two generic types and contains two cases, each of them being able to store an associated value of one of the two generic types.

By convention, we call the cases and the generic types Left and Right.

And thanks to the type Either we now have a convenient way to store inside a single variable a value that can be of one of two types.

Actually the type Either might remind you of another built-in type of Swift called Result.

That’s absolutely normal, because Result is basically identical to Either, the only difference being that the second generic type of a Result must conform to the protocol Error, whereas Either can store values of any type.

So now we’re almost ready to use Either to refactor our code, we just need to make one last addition.

Since a SwiftUI List needs to deal with values that conform to the protocol Identifiable, we’ll declare a conditional conformance, so that Either conforms to Identifiable when both of its generic types also do.

And now it’s finally time to refactor our view!

First, we’ll update the type contained in the Array to use Either

…and then we’ll update the code that builds the rows of the List by switching over the current element and handling each of the two possible cases.

And that’s it: our code has been successfully refactored to meet the new requirement!

That’s all for this article, I hope you’ve enjoyed learning this new trick!

Here’s the code if you want to experiment with it:

import SwiftUI

struct Movie: Identifiable {
    let id = UUID()
    // ....
}

struct Advertisement: Identifiable {
    let id = UUID()
    // ...
}

struct ContentView: View {
    
    @State var content: [Movie]
    
    var body: some View {
        List(content) { movie in
            // display the `movie`
        }
    }
}

enum Either<Left, Right> {
    case left(Left)
    case right(Right)
}

extension Either: Identifiable where Left: Identifiable, 
                                     Right: Identifiable,
                                     Left.ID == Right.ID {
    var id: Left.ID {
        switch self {
        case .left(let left):
            return left.id
        case .right(let right):
            return right.id
        }
    }
}
Next
Next

My highlights of WWDC 2024 as an iOS developer 🍎