Marcel Voss

Enabling Upcoming Swift Language Features

by Marcel on March 22, 2023

Swift 6 has a bunch of changes that will change the way we will use Swift in the future, with some of them being breaking changes. Wouldn’t it be handy if we could try out some of these upcoming features ahead of their release, so we can evaluate the impact they will have on our codebase and can start amending our code already? Good news: there is!

With SE-0362 having been implemented in Swift 5.8, we can now opt-in into certain Swift features ahead of their release, given they’ve been already implemented in the used toolchain version, in a similar fashion as we previouly could with SWIFT_STRICT_CONCURRENCY.

By adding the new compiler flag -enable-upcoming-feature and appending the feature flags we would like to enable to the “Swift Compiler - Custom Flags” section in Xcode, the compiler will enable the selected features for us. For example, if we wanted to enable existential any and strict concurrency checking, we could provide the compiler with this flag: -enable-upcoming-feature ExistentialAny StrictConcurrency. StrictConcurrency here is equivalent to -warn-concurrency, as it exists in Swift 5.7 and earlier.

A screenshot showing the “Build Settings” tab in Xcode with the ‘-enable-upcoming-feature ExistentialAny’ added to the “Swift Compiler - Custom Flags” section.

Currently, these flags are available:

Evolution Proposal Feature Flag
SE-0274 ConciseMagicFile
SE-0286 ForwardTrailingClosures
SE-0335 ExistentialAny
SE-0337 StrictConcurrency
SE-0352 ImplicitOpenExistentials
SE-0354 BareSlashRegexLiterals

Having these feature flags available will certainly make it a lot easier to be prepared for future language versions, and not be as surprised about breaking changes. I suggest enabling them one by one and seeing what they’ll flag in your codebase. It might be surprisingly lot.

Going Further

The same proposal also added a new hasFeature compiler directive that allows us to conditionally use new Swift features, while at the same time still being able to compile our codebase with an older compiler. This can be useful if you want to update your codebase to be ready for when Swift 6 ships to compile with these new features, while still being able to build your code with an older compiler version. Or maybe we would simply like to use these features. Living on the edge!

#if hasFeature(ImplicitOpenExistentials)
  f(aCollectionOfInts)
#else
  f(AnyCollection<Int>(aCollectionOfInts))
#endif

We can even opt into these new language features when we’re developing for a SwiftPM target, as a new function has been added to SwiftSetting that will allow us to tell SwiftPM about the upcoming features we would like to have enabled:

extension SwiftSetting {
  public static func enableUpcomingFeature(
    _ name: String,
    _ condition: BuildSettingCondition? = nil
  ) -> SwiftSetting
}

For a more structured and complete overview of available flags, including explanations of what a certain flag does what, I can highly recommend SwiftyFlags.