some and any keyword in Swift

Shubham Bakshi
4 min readJul 26, 2023

--

Photo by Tolga Ulkan on Unsplash

Discover the enhanced version of the article, complete with refined syntax highlighting and all the latest updates, now available on my personal blog! Your feedback and engagement are greatly appreciated and help fuel future content:

How many times have you encountered the following compilation error:

Protocol ‘Type’ can only be used as a generic constraint because it has Self or associated type requirements

…….. I have, a lot !

Swift 5.7 introduced 2 new keywords: some and any that helps us get rid of this error in the most neat manner

I meant neat manner because prior to Swift 5.7, we could have gotten rid of that error without the use of some and any using generics:

import Foundation

protocol StorageMechanism {
associatedtype TypeOfStorage
}

func implementingStorageFirst(_ mechanism: StorageMechanism) {
// ❌ Will not compile since StorageMechanism
// has associatedtype defined inside it
}

func implementingStorageSecond<T: StorageMechanism>(_ mechanism: T) {
// ✅ Will Compile since we are now using generics
}

func implementingStorageThird(_ mechanism: some StorageMechanism) {
// ✅ Will Compile since we are now using some keyword
}

But as you dive deep into generics with Protocols, you’ll realise some and any are the syntactic sugar that we needed all this time

The main focus of this article is to explain both these keywords through similarities and differences between them. I will be using one of SwiftUI’s protocol View whose declaration primarily looks like:

public protocol View {

associatedtype Body : View
}

Similarities

Both some and any can be used with Protocol that have associatedtype in it (also called as generic protocols)

Consider the following example:

import SwiftUI

// 1. ❌ Will not compile
var var1: View = Text("Sample Text")

// 2. ✅ Will compile
var var2: some View = Text("Sample Text")

// 3. ✅ Will Compile
var var3: any View = Text("Sample Text")

Reasons for the above:

  1. Compilation failed since View has associatedtype Body: View inside it
  2. Compilation succeeds since now we have declared the type with some keyword which acts as opaque type
  3. Compilation succeeds since now we have declared the type with any keyword which acts as existential type

Differences

The real fun starts when you look at the actual differences between the two of them since above code does not clearly states which should be used when

Homogeneous vs Heterogeneous collection behaviour

some only allows homogeneous collection, meaning only similar conforming type are allowed inside the collection. Meanwhile any allows heterogeneous collection meaning any conforming type is allowed inside the collection

Consider the following example:

import SwiftUI

// 1. ✅ Will compile
var var1: [some View] = [ Text("Sample Text"), Text("Sample Text") ]

// 2. ❌ Will not compile
var var2: [some View] = [ Text("Sample Text"), Label("Sample Text", systemImage: "bolt.fill") ]

// 3. ✅ Will Compile
var var3: [any View] = [ Text("Sample Text"), Label("Sample Text", systemImage: "bolt.fill") ]

Reasons for the above:

  1. Compilation succeeds since all the View’s conforming type that are being added to the collection are of same type; and some is good with that 😎
  2. Compilation failed since now we have 2 different conforming types inside the same collection; some gets angry 😤
  3. Compilation succeeds since any is unbothered whether or not the conforming types that are being added to the collection are of same type or not 😴

Similar return type

some only allows same conforming type to be returned; any however is generous and allows any conforming type to be returned

Consider the following example:

import SwiftUI

// 1. ✅ Will compile
var var1: some View {
let random = Int.random(in: 1...5)

if random % 2 == 0 {
return Text("Even")
}
else {
return Text("Odd")
}
}

// 2. ❌ Will not compile
var var2: some View {
let random = Int.random(in: 1...5)

if random % 2 == 0 {
return Text("Even")
}
else {
return Label("Sample Text", systemImage: "bolt.fill")
}
}

// ✅ Will compile
var var3: any View {
let random = Int.random(in: 1...5)

if random % 2 == 0 {
return Text("Even")
}
else {
return Label("Sample Text", systemImage: "bolt.fill")
}
}

Reasons for the above:

  1. Compilation succeeds since we’ll always be returning the same conforming type irrespective of the value of random at runtime; some approves of it 👍
  2. Compilation failed since now different conforming types are being returned; some rejects it 👎
  3. Compilation succeeds since any is unbothered whether or not we’re returning same or different conforming types; typical any 🥱

Now that we are done with the similarities and differences, it’s time for the verdict:

You should always start with some keyword first and if that does not fit your generics use case, switch to any keyword

That is because any relies on a mechanism in programming language called Type Erasure which essentially hides specific type information from code that doesn’t need to concern itself with those types. I won’t be covering that here since that will just add lengths to the article. But you should definitely read about it

That’s it, folks! Happy Coding!

You can connect with me on LinkedIn 👱🏻 or can get in touch with me via other channels 📬

--

--