What is the “any” keyword in Swift?
Published on: March 15, 2022With Swift 5.6, Apple added a new keyword to the Swift language: any
. If you see this in your code, you might think it’s similar to the some
keyword but it’s not quite the same thing.

In-app purchases made easy. RevenueCat provides everything you need to implement, manage, and analyze in-app purchases without managing servers or writing backend code.
Try RevenueCat now
This sponsored message helps keep the content on this site free. Please check out this sponsor as it directly supports me and this site.
Let’s take a look at the any
keyword as it’s intended to be used:
protocol Networking {
func fetchPosts() async throws -> [Post]
// ...
}
struct PostsDataSource {
let networking: any Networking
// ...
}
💡Tip: If you’re not familiar with Swift’s
some
keyword or need a refresher, check out this post on Swift’ssome
keyword.
While the any
keyword might look similar to the some
keyword in the sense that both are used in front of a protocol, and sound like they convey a message similar to “I don’t care what’s used for this type as long as it conforms to this protocol”, they’re really not the same at all.
While some
allows us to write code with generics that more or less ignores, or discards, a protocol’s associated types while expecting that every return value in a function that returns some Protocol
has the same concrete type, the any
keyword simply annotates that a given type is a so-called existential. For the sake of brevity, I won’t cover what an existential is in this post; that’s a topic for a different post.
It's important to know that existentials are relatively expensive to use because the compiler and runtime can’t pre-determine how much memory should be allocated for the concrete object that will fill in the existential. Whenever you call a method on an existential, like the networking
property in the snippet you saw earlier, the runtime will have to dynamically dispatch this call to the concrete object which is slower than a static dispatch that goes directly to the concrete type.
The Swift team has determined that it’s currently too easy to reach for an existential over a concrete object. This essentially means that a lot of us are writing code that uses protocols (existentials) that harm our performance without us really being aware of it. For example, there’s nothing wrong with the following code, right?
protocol Networking {
func fetchPosts() async throws -> [Post]
// ...
}
struct PostsDataSource {
let networking: Networking
// ...
}
I’m sure we all have code like this, and in fact, we might even consider this best practice.
Sadly, this code uses an existential by having a property that has Networking
as its type. This means that it’s not clear for the runtime how much memory should be allocated for the object that will fill in our networking
property, and any calls to fetchPosts
will need to be dynamically dispatched.
By introducing the any
keyword, the language forces us to think about this. In Swift 5.6 annotating our let networking: Networking
with any
is optional; we can do this on our own terms. However, in Swift 6 it will be required to annotate existentials with the any
keyword.
As I was reading the proposal for any
, I realized that what the Swift team seems to want us to do, is to use generics and concrete types rather than existentials when possible. It’s especially this part from the introduction of the proposal that made this clear to me:
Despite these significant and often undesirable implications, existential types have a minimal spelling. Syntactically, the cost of using one is hidden, and the similar spelling to generic constraints has caused many programmers to confuse existential types with generics. In reality, the need for the dynamism they provided is relatively rare compared to the need for generics, but the language makes existential types too easy to reach for, especially by mistake. The cost of using existential types should not be hidden, and programmers should explicitly opt into these semantics.
So how should we be writing our PostsDataSource
without depending on a concrete implementation directly, and without using an existential since clearly existentials are less than ideal?
The easiest way would be to add a generic to our PostsDataSource
and constraining it to Networking
as follows:
protocol Networking {
func fetchPosts() async throws -> [Post]
// ...
}
struct PostsDataSource<Network: Networking> {
let networking: Network
// ...
}
By writing our code like this, the compiler will know up from which type will be used to fill in the Network
generic. This means that the runtime will know up-front how much memory needs to be allocated for this object, and calls to fetchPosts
can be dispatched statically rather than dynamically.
💡Tip: If you’re not too familiar with generics, take a look at this article to learn more about generics in Swift and how they’re used.
When writing PostsDataSource
as shown above, you don’t lose anything valuable. You can still inject different concrete implementations for testing, and you can still have different instances of PostsDataSource
with different networking objects even within your app. The difference compared to the previous approach is that the runtime can more efficiently execute your code when it know the concrete types you’re using (through generics).
The only thing we’ve lost is the ability to dynamically swap out the networking implementation by assigning a new value of a different concrete type to networking
(which we couldn’t do anyway because it’s defined as a let
).
So how useful is the any
keyword really? Should you be using it in Swift 5.6 already or is it better to just wait until the compiler starts enforcing any in Swift 6?
In my opinion, the any
keyword will provide developers with an interesting tool that forces them to think about how they write code, and more specifically, how we use types in our code. Given that existentials have a detrimental effect on our code’s performance I’m happy to see that we need to explicitly annotate existentials with a keyword in Swift 6 onward. Especially because it’s often possible to use a generic instead of an existential without losing any benefits of using protocols. For that reason alone it’s already worth training yourself to start using any
in Swift 5.6.
Using any
now in Swift 5.6 will smoothen your inevitable transition to Swift 6 where the following code would actually be a compiler error:
protocol Networking {
func fetchPosts() async throws -> [Post]
// ...
}
struct PostsDataSource {
// This is an error in Swift 6 because Networking is an existential
let networking: Networking
// ...
}
The above code will need to be written using any Networking
in Swift if you really need the existential Networking
. In most cases however, this should prompt you to reconsider using the protocol in favor of a generic in order to improve runtime performance.
Whether or not the performance gains from using generics over existentials is significant enough to make a difference in the average app remains to be seen. Being conscious of the cost of existentials in Swift is good though, and it’s definitely making me reconsider some of the code I have written.