- Proposal: SE-0441
- Author: James Dempsey
- Review Manager: John McCall
- Status: Accepted
- Implementation: swiftlang/swift-package-manager#7620, swiftlang/swift#75564
- Review: (first pitch) (second pitch) (review) (acceptance)
The term "Swift version” can refer to either the toolchain/compiler version or the language mode. This ambiguity is a consistent source of confusion. This proposal formalizes the term language mode in tool options and APIs.
The proposed solution is to use the term language mode for the appropriate Swift compiler option and Swift Package Manager APIs. Use of "Swift version" to refer to language mode will be deprecated.
The term language mode has been consistently used to describe this compiler feature since it was introduced with Swift 4.0 and is an established term of art in the Swift community.
The Alternatives Considered section contains a more detailed discussion of the term's history and usage.
Introduce a -language-mode option that has the same behavior as the existing -swift-version option, while de-emphasizing the -swift-version option in help and documentation.
The proposed compiler option uses the term 'language mode' instead of 'Swift language mode' because the context strongly implies a Swift language mode. The intent is that the languageMode() compiler condition described in Future directions would also use that naming convention for the same reason.
Introduce four Swift Package Manager API changes limited to manifests >= 6.0:
@available(_PackageDescription, introduced: 6)
Package(
name: String,
defaultLocalization: [LanguageTag]? = nil.
platforms: [SupportedPlatform]? = nil,
products: [Product] = [],
dependencies: [Package.Dependency] = [],
targets: [Target] = [],
swiftLanguageModes: [SwiftLanguageMode]? = nil,
cLanguageStandard: CLanguageStandard? = nil,
cxxLanguageStandard: CXXLanguageStandard? = nil
)Add a new init method to Package with the following changes from the current init method:
- The parameter
swiftLanguageVersionsis renamed toswiftLanguageModes - The parameter type is now an optional array of
SwiftLanguageModevalues instead ofSwiftVersionvalues
The existing init method will be marked as deprecated and renamed allowing the compiler to provide a fix-it.
Rename the public Package property swiftLanguageVersions to swiftLanguageModes. Add a swiftLanguageVersions computed property that accesses swiftLanguageModes for backwards compatibility.
Rename the SwiftVersion enum to SwiftLanguageMode. Add SwiftVersion as a type alias for backwards compatibility.
public struct SwiftSetting {
// ... other settings
@available(_PackageDescription, introduced: 6.0)
public static func swiftLanguageMode(
_ mode: SwiftLanguageMode,
_ condition: BuildSettingCondition? = nil
)The changes in SE-0435: Swift Language Version Per Target have been implemented and released in pre-release versions of Swift 6.0. This proposal will add swiftLanguageMode() as a SwiftSetting and deprecate the swiftLanguageVersion() setting added by SE-0435 with a renamed annotation.
In Swift PM manifests, multiple languages are supported. For clarity, there is existing precedent for parameter and enum type names to have a language name prefix.
For example the Package init method currently includes:
...
swiftLanguageVersions: [SwiftVersion]? = nil,
cLanguageStandard: CLanguageStandard? = nil,
cxxLanguageStandard: CXXLanguageStandard? = nil
...For clarity and to follow the existing precedent, the proposed Swift PM APIs will be appropriately capitalized versions of "Swift language mode".
A new -language-mode option will be added with the same behavior as the existing -swift-version option.
The -swift-version option will continue to work as it currently does, preserving backwards compatibility.
The -language-mode option will be presented in the compiler help.
The -swift-version option will be suppressed from the top-level help of the compiler.
Proposed Swift Package Manager API changes are limited to manifests >= 6.0:
A new init method will be added to Package that renames the swiftLanguageVersions parameter to swiftLanguageModes with the type of the parameter being an optional array of SwiftLanguageMode values instead of SwiftVersion values:
@available(_PackageDescription, introduced: 6)
Package(
name: String,
defaultLocalization: [LanguageTag]? = nil.
platforms: [SupportedPlatform]? = nil,
products: [Product] = [],
dependencies: [Package.Dependency] = [],
targets: [Target] = [],
swiftLanguageModes: [SwiftLanguageMode]? = nil,
cLanguageStandard: CLanguageStandard? = nil,
cxxLanguageStandard: CXXLanguageStandard? = nil
)The existing init method will be marked as deprecated and renamed, allowing the compiler to provide a fix-it:
@_disfavoredOverload
@available(_PackageDescription, introduced: 5.3, deprecated: 6, renamed:
"init(name:defaultLocalization:platforms:pkgConfig:providers:products:
dependencies:targets:swiftLanguageModes:cLanguageStandard:
cxxLanguageStandard:)")
public init(
name: String,
...
swiftLanguageVersions: [SwiftVersion]? = nil,
cLanguageStandard: CLanguageStandard? = nil,
cxxLanguageStandard: CXXLanguageStandard? = nil
) {
See the Source compatibility section for more details about this change.
Rename the Package public property swiftLanguageVersions to swiftLanguageModes. Introduce a computed property named swiftLanguageModes that accesses the renamed stored property for backwards compatibility.
The computed property will be annotated as deprecated in Swift 6 and renamed to swiftLanguageModes.
For packages with swift tools version less than 6.0, accessing the swiftLanguageModes property will continue to work.
For 6.0 and later, that access will be a warning with a fix-it to use the new property name.
@available(_PackageDescription, deprecated: 6.0, renamed: "swiftLanguageModes")
public var swiftLanguageVersions: [SwiftVersion]? {
get { swiftLanguageModes }
set { swiftLanguageModes = newValue }
}See the Source compatibility section for more details about this change.
Rename the existing SwiftVersion enum to SwiftLanguageMode with SwiftVersion added back as a type alias for backwards compatibility. The type alias will be deprecated in 6.0 with a renamed annotation to SwiftLanguageMode.
This change will not affect serialization of PackageDescription types. Serialization is handled by converting PackageDescription types into separate, corresponding Codable types. The existing serialization types will remain as-is.
Add a new swiftLanguageMode() static function to SwiftSetting with the same behavior of swiftLanguageBehavior() added by SE-0435:
public struct SwiftSetting {
// ... other settings
@available(_PackageDescription, introduced: 6.0)
public static func swiftLanguageMode(
_ mode: SwiftLanguageMode,
_ condition: BuildSettingCondition? = nil
)The name of the function is swiftLanguageMode() instead of languageMode() to keep naming consistent with the swiftLanguageModes parameter of the Package init method. The parameter label mode is used to follow the precedent set by the existing interoperabilityMode() method in SwiftSetting.
Deprecate the swiftLanguageVersion() setting added by SE-0435 with a renamed annotation to provide a fix-it for developers who have adopted this API in pre-release versions of Swift 6.0.:
public struct SwiftSetting {
// ... other settings
@available(_PackageDescription, introduced: 6.0, deprecated: 6.0, renamed: "swiftLanguageMode(_:_:)")
public static func swiftLanguageVersion(
_ version: SwiftVersion,
_ condition: BuildSettingCondition? = nil
) -> SwiftSetting {
...
}
}The new Package init method and deprecating the existing init method will cause a deprecation warning for package manifests that specify the existing swiftLanguageVersions parameter when updating to swift tools version 6.0
A search of manifest files in public repositories suggests that about 10% of manifest files will encounter this breakage.
Because the deprecated init method is annotated as renamed the compiler will automatically provide a fix-it to update to the new init method.
Renaming the public swiftLanguageVersions property of Package preserves backwards compatibility by introducing a computed property with that name. The computed property will be marked as deprecated in 6.0 and annotated as renamed to provide a fix-it.
Searching manifest files in public repositories suggests that accessing the swiftLanguageVersions property directly is not common.
The SwiftVersion type alias will be deprecated in favor of the SwiftLanguageMode enum. This also will provide a fix-it.
Finally the swiftLanguageVersion() method in SwiftSetting added as part of SE-0435 will be deprecated in favor of the swiftLanguageMode() method with a fix-it.
This proposal has no effect on ABI stability.
This proposal originally included the proposed addition of a languageMode() compilation condition to further standardize on the terminology and allow the compiler to check for valid language mode values.
That functionality has been removed from this proposal with the intent to pitch it separately. Doing so keeps this proposal focused on the tools, including the source breaking API changes. The future direction is purely additive and would focus on the language change.
In the pitch phase, a number of terms were suggested as alternatives for language mode. Some concerns were also expressed that the term language mode may be too broad and cause future ambiguity.
The intent of this proposal is to formalize established terminology in tool options and APIs.
The term language mode is a long-established term of art in the Swift community to describe this functionality in the compiler.
This includes the blog post announcing the functionality as part of the release of Swift 4 in 2017 (emphasis added):
With Swift 4, you may not need to modify your code to use the new version of the compiler. The compiler supports two language modes…
The language mode is specified to the compiler by the -swift-version flag, which is automatically handled by the Swift Package Manager and Xcode.
One advantage of these language modes is that you can start using the new Swift 4 compiler and migrate fully to Swift 4 at your own pace, taking advantage of new Swift 4 features, one module at a time.
Usage also includes posts in the last year from LSG members about Swift 6 language mode:
Finally, searching for "language modes" and "language mode" in the Swift forums found that at least 90% of the posts use the term in this way. Many of the remaining posts use the term in the context of Clang.
Alternate terms raised as possibilities were:
- Edition: a term used by Rust for a similar concept
- Standard: similar to C or C++ standards
Language standards tend to be associated with a written specification, which Swift does not currently have.
Using the term standard would preclude using the term in the future to describe a formal standard.
Some reviewers raised concern that Embedded Swift could be considered a language mode and lead to future ambiguity.
On consideration, this concern is mitigated in two ways:
-
As noted above, the term language mode is a well-established term of art in the Swift community.
-
The term Embedded Swift already provides an unambiguous, concise name that can be discussed without requiring a reference to modes.
This is demonstrated by the following hypothetical FAQ based on the Embedded Swift vision document:
What is Embedded Swift?
Embedded Swift is a subset of Swift suitable for restricted environments such as embedded and low-level environments.How do you enable Embedded Swift?
Pass the-embeddedcompiler flag to compile Embedded Swift.
Considering these alternatives, it seems likely that introducing a new term to replace the long-established term language mode and potentially giving the existing term a new meaning would lead to more ambiguity than keeping and formalizing the existing meaning of language mode.
Thank you to Pavel Yaskevich for providing guidance and assistance in the implementation of this proposal.