Swift Evolution Monthly: September '22

Conditional Attributes, StaticBigInt, Stable Sorting, Isolated deinit, Work Groups

Swift Evolution Monthly: September '22
Photo by Nick Hillier / Unsplash

After multiple months full of really impactful and fast-paced changes to Swift, such as all the improvements to Generics, the introduction of a shiny new Regex engine, and kicking off the next chapter of programming with distributed actors, things have slowed down a bit in the last two months. This is also the main reason why there was no dedicated monthly issue for August (also, I focused on my first app, which is now scheduled for release on October 11th).

If you are an app developer, probably none of the new proposals I'm summarizing down below is going to cause a "Wow!" reaction, at least it didn't do that for me this time. But I tried to still understand and explain the meaning or direction of each proposal without getting into irrelevant details for app developers.

More interesting topics await you in the Pitches section, which I always sort by my guessed likeliness of interest to the community and limit to a dozen pitches, adding a few more this time as this issue is spanning two months. So if you don't have much time but you still want to know what might be coming next, try reading some of the pitches. The community is discussing great ideas constantly!

Accepted Proposals

The following proposals already presented in the past have been accepted:

On to not yet presented but already accepted proposals!

SE-0367: Conditional compilation for attributes

Links: Proposal Document 📝 | Acceptance Rationale | Review 🧵

Conditional compilation is a language feature very much needed when supporting multiple SDKs (e.g. #if os(iOS)) in an app or multiple Swift versions (e.g. #if swift(>=5.6)) in a framework. The most common use case probably is an #if DEBUG for code that we only want to run during development, but not in production (such as additional logging or different API targets or tokens).

But currently, if you wanted to conditionally use Swift attributes such as @objc or the newer @preconcurrency (for code that was written without Swift Concurrency in mind, see SE-0337), you'd have to duplicate the code for the entire thing the attribute applies to, such as for an entire type like in this example:

#if compiler(>=5.6)
   @preconcurrency
   protocol P: Sendable {
      func f()
      func g()
   }
#else
   protocol P: Sendable {
      func f()
      func g()
   }
#endif

From Swift 5.8 onwards we will be able to shorten that code to just this:

#if hasAttribute(preconcurrency)
   @preconcurrency
#endif
protocol P: Sendable {
   func f()
   func g()
}

Note the new hasAttribute conditional directive. This not only prevents duplicate code but also more clearly states why we were using a conditional compilation here (because of the attribute!) and saves us the time of having to look up which Swift version the attribute was introduced in.

SE-0368: StaticBigInt

Links: Proposal Document 📝 | Acceptance Rationale | Review 🧵

Unless you're working on a mathematical app or framework, you probably won't need to know about the new StaticBigInt type introduced here. But if you do, you might want to read the full proposal (it's short enough) to learn how you can define your own large integer types that support literals that don't fit into [U]Int64.

Maybe also worth noting that the official swift-numerics library might soon get larger integer types such as [U]Int256 once this was accepted.

SE-0369: Add CustomDebugStringConvertible conformance to AnyKeyPath

Links: Proposal Document 📝 | Acceptance Rationale | Review 🧵

This proposal aims at improving the printing of key paths such as in print(\User.name) from currently resulting in Swift.KeyPath<User, String> which is not very useful, to result in something closer to the call like \User.name.

This small improvement could help in debugging and make unit tests clearer.

SE-0370: Pointer Family Initialization Improvements and Better Buffer Slices

Links: Proposal Document 📝 | Acceptance Rationale | Review 🧵

This is a low-level programming improvement that is not relevant for most app developers. For those interested in low-level, the title should clarify the topic.

SE-0372: Document Sorting as Stable

Links: Proposal Document 📝 | Acceptance Rationale | Review 🧵

Imagine you have an array of books in code, something like this:

var books: [Book] = [
   .init(author: "Robert Galbraith", title: "The Cuckoo's Calling"),
   .init(author: "J. R. R. Tolkien", title: "The Fellowship of the Ring"),
   .init(author: "J. R. R. Tolkien", title: "The Two Towers"),
   .init(author: "J. R. R. Tolkien", title: "The Return of the King"),
]

And you call books.sort(by: { $0.author < $1.author }), you would expect that the three Lord of the Rings books from J. R. R. Tolkien would be sorted above the first Cormoran Strike book by J. K. Rowling, right? You're right, of course.

But would you also expect the three Lord of the Rings books to remain in the right order, starting with "The Fellowship of the Ring"? I guess you would. It's how humans would naturally sort. But technically speaking, all three Lord of the Rings books have the same author, and therefore the sorting criteria treats them all like they're on the same level. How elements that are on the same level are treated depends on the sorting algorithm. Algorithms that preserve the order of equal-level elements are called "stable".

In Swift, the sort function has been implemented as a "stable" algorithm for multiple years now, but it was never documented to be. So in theory, the implementation of future versions could have changed to a non-stable algorithm. Not anymore: This proposal documents the sort function's behavior to be stable.

Proposals In Review/Revision/Awaiting Decision

You can still provide feedback for these proposals. The current rejection rate is <10%, so they're likely to get accepted. Revisions are more common.

These proposals already presented in the past were returned for revision:

On to new proposals in review/revision/decision!

SE-0371: Isolated synchronous deinit

Links: Proposal Document 📝 | Review 🧵 | Revision Rationale 🔁

This proposal is another one that probably won't sound like a huge deal to most app developers. Especially because most didn't have the chance to make full use of actor types yet (including myself). Introduced with SE-306 in Swift 5.5, they help deal with concurrently executed logic that "acts" on the same data in parallel. A good sign that you should probably consider using them more is when you have classes as data models in your app. Chances are that you might be accessing them simultaneously. And migrating them over to actor types should be possible, given that actors are also reference types like classes.

In Swift, it's common for types that hold onto other data or dependencies to automatically get rid of these in a deinit method, rather than requiring a close() like method that needs to be explicitly called. When initializers were settled in the Swift actor world with SE-0237, the deinitializer's access was limited to Sendable stored properties only. All value types ( enums, structs) and all immutable reference types ( classes) can be easily marked as Sendable, which means the data is safe to pass across threads. This proposal weakens that limitation by being smart about the details of the state without compromising safety. This allows a deinit function to additionally access some non- Sendable state, preventing the need of having to provide a close() function or do internal reference counting.

While I don't fully understand this proposal's impact even after reading it twice, it sounds a lot like a "rounding things off" kind of proposal to me, which we will all appreciate once we got more used to writing actor types. Currently, I guess, it mostly affects Server-side Swift developers and lower-level framework authors.

📧
To receive future issues via email, subscribe to the newsletter here.

Recently Active Pitches/Discussions

Some threads inside the “Evolution” category with activity within the last 2 months I didn’t link yet. I’ll cover them in detail once (and if) they become proposals:

Other Developments worth Mentioning

It's great to see that there are plans to implement parts of the Swift compiler in Swift (I know, it sounds like an infinite recursion to use Swift for Swift, but it works because the latest development Swift is built with the latest stable release Swift, which was at some point built without any Swift involved [mostly C++]).

The 6 currently existing workgroups (Language, C++ Interoperability, Server, Swift.org website, Documentation, and Diversity) might soon be joined by new groups: Besides Numerical/ML mentioned in the May issue already, one for Swift Tooling and one for broader Platform Support were recently discussed. I also found an older discussion about an Embedded/Bare Metal/Low Resources group. All of these groups make a lot of sense to me, so I hope they will be successful!

That’s it from my September update!

👤
Want to Connect?
Follow me on 👾 Twitch, on 🎬 YouTube, and on 🐦 Twitter.