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
}
}
}