The “some” keyword in Swift

Paul O'Neill
4 min readMar 10, 2023

--

If you have started writing your UI Code in SwiftUI, you surely have noticed the “some” keyword in the body variable of a View:

var body: some View { ... }

While the “some” keyword has been in Swift for a little while, there have been some new updates on how to use it with Swift 5.7. In this article, I’d like to talk about what the “some” keyword means and when and how we can use it.

This keyword is one way to express generics in Swift. Generics can help you achieve polymorphism, or more specifically, parametric polymorphism. Here’s an example:

struct Company {
func hire(_ employee: ???) { ... }
}

Here we have a company struct that has a function to hire new employees. Since employees with different titles do different work, we created separate structs for the different positions. Since they all do some kind of work, we created a protocol Employee to encapsulate what each employee has in common.

protocol Employee {
func doesWork() { ... }
}

struct Accountant: Employee {
func doesWork() { ... }
}

struct Engineer: Employee {
func doesWork() { ... }
}

struct UXDesigner: Employee {
func doesWork() { ... }
}

In the Company struct, the hire method takes some type of employee struct, but we don’t know what type yet. With our new Employee protocol we can now ensure that whatever the hire method takes, it conforms to this protocol. To do that you can write that function like this:

func hire<E>(_ employee: E) where E: Employee

We specify in this function a generic parameter that must conform to the Employee protocol. This code works, but it does seem like it’s more complex than it actually is. With the updates to Swift 5.7, we can now use the “some” keyword in a parameter and rewrite this method like so:

func hire(_ employee: some Employee)

Cool, right? The function hire takes some Employee type. Not only is this clearer, but it’s more readable and cleaner to write. This is one of my favorite additions to Swift!

How does the “some” keyword work?

The “some” keyword represents an opaque type. In our case, this is the Employee protocol. Engineer, Accountant, and UXDesigner represent concrete types or the underlying types. As we learned above, this works exactly like the previous generic function before. Because of this, the function needs to be tied to one concrete type. For example, the following code will not compile:

func hireEmployee(_ candidate: Candidate) -> some Employee {
if candidate.hasComputerHackingSkills {
return Engineer()
}

if candidate.hasNumberSkills {
return Accountant()
}

if candidate.hasDesignSkills {
return UXDesigner()
}
}

You will get the following error:

Function declares an opaque return type ‘some Employee’, but the return statements in its body do not have matching underlying types

There are multiple different concrete (or underlying) types that could be returned in this method. In order for this function to work, we need to make sure that all return statements return the same underlying type. Doing so will give this piece of code the static-type performance we can get with generics.

With this knowledge, let's jump back into SwiftUI. From what we just learned above we should now know that this doesn’t compile:

var makeView: some View {
if self.showButton {
return Button("Hello, World") {}
} else {
return Text("Hello, World")
}
}

This method returns some View but there are two different concrete types returned. This makes sense why it doesn’t compile. There is a way to fix this.

@ViewBuilder
var makeView: some View {
if self.showButton {
Button("Hello, World") {}
} else {
Text("Hello, World")
}
}

Adding the @ViewBuilder annotation and removing the return statements, we allow our view to be built as one wrapper type. That type is now _ConditionalContent<Button<Text>, Text> which conforms to View. Pretty, slick.

When should I not use the “some” keyword

Using the “some” keyword is a great way to represent a simple generic statement. But there are some times when using the old way is necessary. For example, when you need to refer to the opaque type multiple times in the method signature, using the “some” keyword won’t work. See the code below:

protocol Employee {
associatedtype PayStructure: PayType
func perform(_ work: Work)
}

struct Accountant: Employee {
typealias PayStructure = AccountantPayStructure

func perform(_ work: Work) { ... }

func getPayStructure<E>(for employee: E) -> E.PayStructure where E: Employee, E.PayStructure == PayStructure {}
}

Here we added an associated type to the Employee protocol for handling the pay structure for the underlying type of the Employee protocol. We create a method to get the pay structure, but in this case, we specify that we only want the pay structure for the underlying type. Since the opaque type needs to be mentioned several times in the method signature, this is not a good case for using the “some” keyword.

Another instance where the “some” keyword should not be used is with generic types.

struct PayCheck<Currency> {
let currency: Currency

init(currency: Currency) {
self.currency = currency
}
}

let paycheck: PayCheck<USD>

Below we specify the generic type in multiple places. This design pattern is useful when explaining and visualizing what that type does. But the “some” keyword doesn’t make sense here.

Summary

We learned that the “some” keyword signifies an opaque type and as of Swift 5.7, we can replace a named generic method signature with the “some” keyword in simple cases. This brings clarity and simplicity to your code.

Thanks for reading! Please follow me for regular Apple development content.

--

--