- Proposal: SE-0141
- Author: Graydon Hoare
- Review Manager: Doug Gregor
- Status: Implemented (Swift 3.1)
- Decision Notes: Rationale
- Bug: SR-2709
Swift's existing @available(...)
attribute indicates the lifecycle of a
given declaration, either unconditionally or relative to a particular
platform or OS version range.
It does not currently support indicating declaration lifecycle relative to Swift language versions. This proposal seeks to extend it to do so.
Swift-evolution threads: Draft, Review
As the Swift language progresses from one version to the next, some
declarations will be added, renamed, deprecated or removed from the
standard library. Existing code written for earlier versions of Swift will
be supported through a -swift-version N
command-line flag, that runs the
compiler in a backward-compatibility mode for the specified "effective"
language version.
When running in a backward-compatibility mode, the set of available
standard library declarations should change to match expectations of older
code. Currently the only mechanism for testing a language version is the
compiler-control statement #if swift(>= N)
which is a static construct:
it can be used to compile-out a declaration from the standard library, but
evolving the standard library through this mechanism would necessitate
compiling the standard library once for each supported older language
version.
It would be preferable to compile the standard library once for all
supported language versions, but make declarations conditionally
available depending on the effective language version of a user of the
library. The existing @available(...)
attribute is similar to this
use-case, and this proposal seeks to extend the attribute to support it.
The @available(...)
attribute will be extended to support specifying
swift
version numbers, in addition to its existing platform versions.
As an example, an API that is removed in Swift 3.1 will be written as:
@available(swift, obsoleted: 3.1)
class Foo {
//...
}
When compiling user code in -swift-version 3.0
mode, this declaration
would be available, but not when compiling in subsequent versions.
The token swift
will be added to the set of valid initial arguments
to the @available(...)
attribute. It will be treated similarly,
but slightly differently, than the existing platform arguments. In
particular:
-
As with platform-based availability judgments, a declaration's
swift
version availability will default to available-everywhere if unspecified. -
A declaration's
swift
version availability will be considered in logical conjunction with its platform-based availability. That is, a given declaration will be available if and only if it is both available to the current effectiveswift
version and available to the current deployment-target platform. -
Similar to the abbreviated form of platform availability, an abbreviated form
@available(swift N)
will be permitted as a synonym for@available(swift, introduced: N)
. However, addingswift
to a platform availability abbreviation list will not be allowed. That is, writing the following examples is not permitted:@available(swift 3, *)
@available(swift 3, iOS 10, *)
This restriction is due to the fact that platform-availability lists are interpreted disjunctively (as a logical-OR of their arguments), and adding a conjunct (logical-AND) to such a list would make the abbreviation potentially ambiguous to readers.
Existing code does not use this form of attribute, so will not be affected at declaration-site.
As declarations are annotated as unavailable or obsoleted via this attribute, some user code may stop working, but the same risk exists (with a worse user experience) in today's language any time declarations are removed or conditionally-compiled out. The purpose of this proposal is to provide a better user experience around such changes, and facilitate backward-compatibility modes.
The main alternative is compiling libraries separately for each language
version and using #if swift(>=N)
to conditionally include varying APIs.
For a library used locally within a single project, recompiling for a
specific language version may be appropriate, but for shipping the standard
library it is more economical to compile once with all declarations, and
select a subset based on language version.