We are incredibly excited to embark on one of our most ambitious series ever on Point-Free. We are going beyond the basics by cover 3 major topics in the Swift programming language that allow you to express powerful invariants in your code. When used properly you can construct APIs for you and your team to use so that the Swift compiler naturally guides you to the correct usage. Things that should not be possible will be provably impossible, enforced by the compiler.
These three topics are as follows:
Isolation: By far the most important concept in Swift concurrency is that of “isolation”. It is a static, compiler enforced guarantee that a particular region of your code will never be simultaneously accessed from multiple threads. There are a lot of misconceptions in the Swift community about what isolation is and just how viral it can be here, and we are here to bust those myths. We will show that one can embrace isolation without literally making everything in your code async and having to sprinkle awaits everywhere.
Next we will talk about non-copyable types. These are types with very strict ownership rules that prevent making unnecessary copies of data and restrict how the data can be passed around to functions. One of the super powers of non-copyable types is their ability for you to pass values around without ever incurring the cost of making copies.
And finally we will talk about non-escapable types. This is a very new tool in Swift, and is still in active development, but the fundamentals are in place and ready for use. Non-escapable types allow you to be strict with how long values can live and tie their lifetimes to the lifetimes of other values. This goes hand-in-hand with non-copyable types for even more power, and in a (hopefully) near future it will even allow for storing non-escaping closures in types, which would allow us to build powerful abstractions that do not incur the cost of thunks, heap allocation, and deep call stacks.
These three tools, when used together, allow you to highly restrict how your APIs can be used so that you can provide the safest possible tools, and amazingly the tools can even be more performant!
So, we have a lot to cover, but before getting into the nitty-gritty of these advanced Swift topics, we are going to have a little fun by giving everyone a sneak peek at some of the amazing things we have been able to build with these tools.
We will first show how we use these tools to build the next generation of the Composable Architecture, and in particular the
Storeconcept. We have been able to strongly control the isolation that features execute in, which gave us the ability to support main actor stores and background stores at once (with no code duplication), and provide stronger guarantees on how effects execute, which allows tests to run deterministically without sprinklingTask.yields all over the place. And this will all be accomplished while minimizing how much we need to employ sendable types and closures, making it very easy to use, and without using locks to enforce correctness, greatly improving performance.
And then we will show how we can use these tools to build a Swift wrapper around a popular C library that enforces the requirements of that C library statically. Anytime you deal with a C library you are naturally going to have to deal with pointers, which are notoriously difficult objects to correctly handle. Add on top of that this particular C library has additional restrictions on when it is and is not OK to call its methods from multiple threads, and you have a veritable minefield ahead of you that is easy to get wrong. But we will show how one can enforce correctness at compile time, and again, all without decorating every type under the sun with
Sendableand using locks all over the place.
I hope all of this sounds exciting because it’s hard to put into words just how amazing it all is. The only way to really see it is to show it. So let’s begin.