The article discusses enhancements to the some and any keywords in Swift 5.7, which improve the syntax and capabilities of generic code, allowing for cleaner code and new programming paradigms.
Abstract
Swift 5.7 introduces significant improvements to the some and any keywords, enhancing the way developers write generic code. The some keyword, introduced in Swift 5.1, now allows for opaque types in function parameters, providing a cleaner syntax for generic functions. The any keyword, added in Swift 5.6, is now mandatory for creating existential types and can be used with protocols with associated types, overcoming previous limitations. These updates enable developers to create heterogeneous arrays and achieve dynamic dispatch with generic protocols more straightforwardly. While existential types offer flexibility, they come with limitations such as the inability to use the == operator for comparison and reduced efficiency compared to opaque types. The article emphasizes the benefits of these enhancements for Swift developers and suggests using the some keyword when possible for efficiency.
Opinions
The author believes that the improvements to the some and any keywords are a welcome change, making generic code in Swift more readable and efficient.
The author points out that the new capabilities eliminate the need to deal with the error message "protocol can only be used as a generic constraint because it has Self or associated type requirements," which was a common frustration for Swift developers.
There is an appreciation for the flexibility that the any keyword brings, especially in allowing protocols with associated types to be used in creating heterogeneous arrays.
The author acknowledges the limitations of existential types, such as the inability to compare instances and reduced efficiency, but still views them as a valuable tool in the right context.
The author recommends following the updates from Apple's WWDC sessions to stay informed about the latest advancements in Swift and suggests using the some keyword when the task at hand allows for it due to its efficiency advantages over existential types.
Understanding the “Some” and “Any” Keywords in Swift 5.7
No more confusion!
The some and any keywords are not new in Swift. The some keyword was introduced in Swift 5.1 whereas the any keyword was introduced in Swift 5.6. In Swift 5.7, Apple makes another great improvement on both of these keywords. We can now use both of these keywords in the function’s parameter position!
This improvement not only made the generic functions look a lot cleaner, but also unlocked some exciting new ways to write generic code in Swift. Spoiler alert — we can now say goodbye to the following error message:
protocol can onlybe used asa generic constraint because it has Self or associated type requirements
Want to know more? Read on!
First Things First
Before getting into the details, let’s define the protocol we will be using throughout this article.
After that, we will define a Car and a Bus struct that conforms to the Vehicleprotocol and each of them will require different kinds of fuels. Here’s the code:
Notice that the fillGasTank(with:) function’s parameter data type of Car and Bus are not the same, Car requires Gasoline whereas Bus requires Diesel. That is why we need to define an associated type called FuelType in our Vehicleprotocol.
With that out of the way, let’s dive right into the details, shall we?
Understanding the “some” Keyword
The some keyword was introduced in Swift 5.1. It is used together with a protocol to create an opaque type that represents something that is conformed to a specific protocol. When used in the function’s parameter position, it means that the function is accepting some concrete type that conforms to a specific protocol.
At this stage, you might be wondering, aren’t we already able to do that?
In fact, you are right. Using the some keyword in the function’s parameter position is exactly the same as using the angle brackets or a trailing where clause at the function signature.
When we use the some keyword on a variable, we are telling the compiler that we are working on a specific concrete type, thus the opaque type’s underlying type must be fixed for the scope of the variable.
One interesting point to be aware of is that assigning a new instance of the same concrete type to the variable is also prohibited by the compiler.
With that in mind, we will have to follow the same rule when using it with an array.
The same goes for the underlying return type of a function.
That’s all for the some keyword. Let’s head over to the any keyword and see what are the differences between them.
Understanding the “any” Keyword
The any keyword was introduced in Swift 5.6. It is introduced for the purpose of creating an existential type. In Swift 5.6, the any keyword is not mandatory when creating an existential type, but in Swift 5.7, you will get a compile error if you failed to do so.
As explained by Apple engineers, an existential type is like a box that contains something that conforms to a specific protocol.
Comparing the some and any keyword
As illustrated in the image above, the main difference between an opaque type and an existential type is the “box.” The “box” enables us to store any concrete type within it as long as the underlying type conforms to the specified protocol, thus allowing us to do something that an opaque type doesn’t allow us to do.
The best part is that, in Swift 5.7, we can now use the any keyword for protocols with associated types! This means that creating a heterogeneous array using a protocol with associated types is no longer a limitation!
How cool is that? 😃
This improvement not only eliminated the “protocol can only be used as a generic constraint because it has Self or associated type requirements” error, but it also makes accomplishing dynamic dispatch on protocol with associated types a lot more straightforward! But that will be an article for another day.
The “any” Keyword Limitations
As good as it might seem, the existential type created using the any keyword still has its own limitations. One major limitation is that we cannot use the == operator to compare two instances of the existential type.
If you think about it, this actually kind of makes sense. As mentioned earlier, an existential type can have any concrete type stored in its “box”. To the compiler, an existential type is just a “box”, it has no idea what’s inside the box. Therefore, it is not possible for the compiler to make a comparison when it cannot guarantee that the content of the “box” has the same underlying concrete type.
Another limitation that you should be aware of is that the existential types are less efficient than the opaque types (created using the some keyword). Donny Wals has a great article that discusses this in much detail, I highly recommend you to check it out.
Therefore, even though Apple has made a lot of improvements on the any keyword, it is still recommended to use the some keyword if the opaque types can get the job done.
The improvements to the any and some keywords in Swift 5.7 is definitely a welcome one. On one hand, it drastically improved the syntax and readability of our generic code. On the other hand, it opens up new ways for us to write generic code in a much more efficient manner.
I hope this article gives you a good look into the any and some keyword. Feel free to follow me on Twitter so that you won’t miss out on any of my upcoming articles.