Swift Evolution Monthly: January '24
Smoothing out some rough edges in Swift concurrency. System-level programming with low-level atomics. And many interesting new proposals linked!
Thanks to Antoine's idea to point to other related newsletters upon subscribing, the number of people receiving this issue more than doubled within the last month, so hello and welcome on board to everyone new! 👋
January was also quite a busy month for me personally. Just as a mini recap, I shipped a huge 2.0 update to my puzzling game CrossCraft and I released a new developer app – TranslateKit – after weeks of frustration due to nonsensical rejections by the Review team. 😩 I'd love you to give both a try! The latter even launched on Product Hunt today. 👀
Note that I migrated CrossCraft to visionOS for day 1 of the Apple Vision Pro and even live-streamed the entire process here. I will upload a shorter video there. Speaking of the Vision Pro, I also released another app which I specifically developed for it to fix a flaw in the visionOS user interface. 🕓🔋
On other news, the swift.org website underwent a redesign. I really like how the crowded sidebar was replaced with a more organized top bar! Good job. 👏
Accepted Proposal Summaries
SE-0410: Low-Level Atomic Operations
Links: 📝 Proposal | 💬 Reviews: 1st, 2nd | ✅ Acceptance
This introduces low-level synchronization primitives hidden behind a module named Synchronization
that you need to explicitly import to use them. App developers should probably stick to the recently introduced concurrency features like async/await
, but for Swift to be successful as a systems programming language, new low-level APIs like the Atomic
type introduced here are important. Some libraries also might use it internally.
SE-0416: Subtyping for keypath literals as functions
Links: 📝 Proposal | 💬 Review | ✅ Acceptance
This small proposal allows using key paths in some situations that were previously impossible. For example, the compiler is currently not able to convert the Int
to an Int?
(like it can in other contexts) in following code:
struct Person {
var age: Int
}
// error: Key path value type 'Int' cannot be converted to contextual type 'Int?'
let x: (Person) -> Int? = \.age
In the future, key paths will work in more situations, including the above.
SE-0417: Task Executor Preference
Links: 📝 Proposal | 💬 Review | ✅ Acceptance
This proposal is mostly for improving the performance on event-loop based systems like network servers. It introduces a new flexible mechanism for developers to tune their applications and avoid potentially unnecessary context switching when using Swift concurrency. Read the full proposal if this affects you. Most app developers probably are good with the current defaults.
SE-0418: Inferring Sendable for methods and key path literals
📝 Proposal | 💬 Review | ✅ Acceptance
This one improves flexibility, simplicity, and ergonomics in some edge cases by inferring @Sendable
in more situations surrounding functions as values and key path literals. As a quick reminder, the Sendable
protocol indicates that a type is safe to be passed to other Tasks and Actors in Swift concurrency. You've probably already seen warnings in some places when using async/await
. In Swift 6, some (or all?) of those warnings will become compiler errors, so it's good news that Sendability is inferred in more situations to reduce friction when entering the world of more strict safety.
SE-0420: Inheritance of actor isolation
📝 Proposal | 💬 Review | ✅ Acceptance
Here's another change that will reduce the friction around Sendable
types in Swift 6. The purpose of this proposal is to allow non-Sendable
data to be safely passed to functions by inheriting the isolation context. An isolated
keyword (introduced in SE-0313) can be put in front of actor types alongside an #isolation
expression as a default value to achieve that. As a result, functions might get declared like this:
func foo(isolation: (any Actor)? = #isolation) async
If you want to learn more about the isolated
keyword, the same Antoine I mentioned at the beginning has written a great article about it.
All in all, I really like the continued effort in Swift to make concurrency work more smoothly in more situations. I have a feeling that Swift 6 isn't too far off anymore, given that we are seeing more edge cases being tackled. Maybe later this year? 🤞
Proposals in Progress
- SE-0403: Package Manager Mixed Language Target Support
📝 Proposal | 💬 Review | 🔄 Returned - SE-0406: Backpressure support for AsyncStream
📝 Proposal | 💬 Review | 🔄 Returned - SE-0414: Region based Isolation
📝 Proposal | 💬 Reviews: 1st, 2nd - SE-0415: Function Body Macros
📝 Proposal | 💬 Review | 🔄 Returned - SE-0416: Subtyping for keypath literals as functions
📝 Proposal | 💬 Review | 🔄 Returned - SE-0419: Swift Backtracing API
📝 Proposal | 💬 Review - SE-0421: Generalize effect polymorphism for AsyncSequence & AsyncIteratorProtocol
📝 Proposal | 💬 Review - SE-0422: Expression macro as caller-side default argument
📝 Proposal | 💬 Review
Noteworthy Active Threads
- Resolve DistributedActor protocols (for server/client apps)
- Default values for string interpolations
- Future of Codable and JSON-Coders in Swift 6: Hoping for a rework
- Unicode Processing APIs
- Async support in defer blocks?
- Non-Escapable Types and Lifetime Dependency
- Synchronous Mutual Exclusion Lock
- Enable bounds-checking for BufferPointers
- Safe Access to Contiguous Storage
- Low-level linkage control
- Low-level operations for volatile memory accesses
I love how Swift is becoming more widely usable, which I'm sure will make it a better language for app developers, too.
I'm also particularly excited about the first link in the "Active Threads" section. If I understood it correctly on a quick read, it has the potential to make away with the need to write API clients for servers altogether, hiding the client-server communication in a distributed actor. Check it out!
That was it for January. Don't forget to try CrossCraft & TranslateKit! 🌟🙏