Swift Evolution Monthly: May '23

"package" Modifier, Noncopyable structs/enums, Custom Actor Executors, Freestanding Declaration Macros, more Packs.

Swift Evolution Monthly: May '23
Photo by Natalia Arkusha / Unsplash

WWDC is rapidly approaching – and if last year is any sign, then many of the proposals covered in past issues and down below in this one will be an integral part of the session videos: Either because Apple introduces new APIs only possible thanks to recent changes in Swift, or simply to give developers advice on how to make use of Swifts latest features. As many things are going on in the community right now inspired by WWDC, I will try to keep this issue as short as possible.

I don't want to skip these two topics though:

  1. The WWDC Notes project is more active than ever this year. With the help of the community, we aim to cover 80% of all sessions within the first week. Over 20 volunteers joined within a few days, and we are looking for more contributors. If you're unable to watch many sessions, you can still help (and profit) by contributing notes for one or two sessions. Together, we can achieve a lot. Join us on Slack & send me the topics you're interested in to get involved!
  2. To celebrate WWDC within my own work, I decided to add some useful and completely free features to my developer-focused app RemafoX. Also, there's a massive sale during WWDC for those interested in its advanced features. I'll leave you with a GIF demoing the new free features:

Accepted Proposals

7 new proposals were accepted in May, so I'm skipping on the old one this time.

SE-0386: New access modifier: package

Links: 📝 Proposal | 💬 Reviews: 1st, 2nd | ✅ Acceptance

Currently, Swift library authors that like to split their code into separate modules have to use the public access modifier to make any APIs available from one (helper) module to another. This makes these APIs available to all users of the package, even if the API is not intended for public use. Library authors have to stick to a single module design to actually keep helper functions internal to the package.

Not anymore! The new access modifier package can be used in the future to mark any API as "internal to the package", making it available to other modules within the same package, but not accessible to users of the package. 🎉

SE-0390: Noncopyable structs and enums

Links: 📝 Proposal | 💬 Reviews: 1st, 2nd | ✅ Acceptance

In Swift, we currently have value types (like struct) and reference types (like class). We use value types to represent blobs of data that are implicitly copied when we pass them along to other functions. We use reference types whenever we don't want this copying behavior and instead want to pass a pointer so there's a single object that can be changed by other functions directly.

This proposal introduces a third concept that can be often used in place of a class in the future: A "noncopyable" type. You can create a struct and conform it to ~Copyable (read: "suppress Copyable") and when passing it along to functions, it won't be copied implicitly. But unlike classes, there's no overhead of storing the data in the heap (saves memory) or reference counting (saves CPU cycles).

The example provided in the proposal is a FileDescriptor:

struct FileDescriptor: ~Copyable {
  private var fd: Int32

  init(fd: Int32) { self.fd = fd }

  func write(buffer: Data) {
    buffer.withUnsafeBytes { 
      write(fd, $0.baseAddress!, $0.count)
    }
  }

  deinit {
    close(fd)
  }
}

Note that noncopyable structs can have a deinit method, which normal structs can't have.

There are some requirements for nested types (they need to be ~Copyable, too) and limitations for generic types (see workarounds). But this sounds like it's going to change some current Best Practices about correct and performant Swift code. Read this section to learn more about the usage of noncopyable types.

SE-0392: Custom Actor Executors

Links: 📝 Proposal | 💬 Reviews: 1st, 2nd | ✅ Acceptance

This proposal introduces the concept of custom executors and customization points in Swift Concurrency, providing developers with greater control over the execution semantics of their actors. I'm not in a position to customize executors, so I can't provide practical implications. But the motivation section ends with this:

Along with introducing ways to customize where code executes, this proposal also introduces ways to assert and assume the appropriate executor is used. This allows for more confidence when migrating away from other concurrency models to Swift Concurrency.

SE-0396: Conform Never to Codable

Links: 📝 Proposal | 💬 Review | ✅ Acceptance

This is probably the shortest proposal I've ever summarized, so let's keep it short: The proposal suggests adding Codable conformance to the Never type in Swift. This allows encoding but throws an error for decoding attempts, addressing a limitation with generic types that involve Never, like Either<Int, Never>.


Want to see your ad here? Contact me at ads@fline.dev to get in touch.

SE-0397: Freestanding Declaration Macros

Links: 📝 Proposal | 💬 Reviews: 1st, 2nd | ✅ Acceptance | 🔮 Vision

The proposal extends Swift's macros to allow generating declarations, enabling use cases like generating data structures from templates or introducing warning/error directives as macros. It introduces freestanding declaration macros that use the # syntax and have type-checked arguments, producing zero or more declarations. For example, the #warning directive from SE-0196 can be declared as a freestanding declaration macro like so:

@freestanding(declaration) 
macro warning(_ message: String) = #externalMacro(module: "MyMacros", type: "WarningMacro")

The implementation part is a bit more involved like with any other macros though.

SE-0398: Allow Generic Types to Abstract Over Packs

Links: 📝 Proposal | 💬 Review | ✅ Acceptance

This introduces the ability to use generic types to abstract over packs of types. It generalizes the concepts introduced in SE-0393, which allowed generic function declarations to abstract over a variable number of types (each T). With this proposal, you can define generic type declarations that abstract over multiple types, enabling the creation of more flexible and generalized algorithms.

This allows defining functions like zip where the return type needs an arbitrary number of type parameters – one for each input sequence:

func zip<each S>(_ seq: repeat each S) -> ZipSequence<repeat each S>
  where repeat each S: Sequence

The return type ZipSequence<repeat each S> is what this proposal allows.

SE-0399: Tuple of value pack expansion

Links: 📝 Proposal | 💬 Review | ✅ Acceptance

Also building upon SE-0393, this one enables referencing a tuple value that contains a value pack inside a pack repetition pattern. Currently, there is no way to reference individual elements of a value pack within a tuple or pass them as arguments to a function. This proposal fills that gap by allowing pack repetition patterns to operate on tuple values containing value packs, providing a method to access individual value pack elements within a tuple. For example:

func tuplify<each T>(_ value: repeat each T) -> (repeat each T) {
  return (repeat each value)
}

func example<each T>(_ value: repeat each T) {
  let abstractTuple = tuplify(repeat each value)
  repeat print(each abstractTuple) // okay as of this proposal
}

Proposals in Progress

Recently Active Pitches/Discussions

Other Developments Worth Mentioning

If you want to enable Swift 6 features today, James Dempsey wrote a detailed article on the Swift blog just a few days ago on how to do that. I had already enabled "Swift 6" mode in April in my apps and documented my experience here.

Lastly, the Swift Core Team announced changes to how workgroups are named and operate in this blog post. Basically, there will be two tiers of groups: steering groups, responsible for overall strategic direction, and workgroups, focused on specific areas of the project. The core mission of diversity will be incorporated into all workgroups. Additionally, the Ecosystem Steering Group will be formed to support the Swift developer ecosystem, and a Contributor Experience Workgroup will create pathways for open-source contributions. Here's an overview of all:

Swift Workgroups Diagram
Source: swift.org

And that's it for May. Have a great week of WWDC 😎 and until next time!

💁🏻‍♂️
Enjoyed this article? Check out TranslateKit!
A drag & drop translator for String Catalog files – it's really easy.
Get it now to machine-translate your app to up to 150 languages!
👨🏻‍💻
Want to Connect?Follow me on 👾Twitch, 🎬YouTube, 🐦Twitter, and 🦣Mastodon.