[Draft] Availability by Swift version

Hi,

The following is a proposal for a very minor extension of the @available system. Hopefully uncontroversial!

Thanks,

-Graydon

# Availability by Swift version

* Proposal: [SE-NNNN](NNNN-available-by-swift-version.md)
* Authors: [Graydon Hoare](https://github.com/graydon\)
* Review Manager: TBD
* Status: **Awaiting review**

## Introduction

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.

## Motivation

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.

## Proposed solution

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.

## Detailed design

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 effective `swift` 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, adding `swift` 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.

## Impact on existing code

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.

## Alternatives considered

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.

I wish we had this feature all along. It’ll be a great addition for library authors. +1

···

On Sep 22, 2016, at 10:18 AM, Graydon Hoare via swift-evolution <swift-evolution@swift.org> wrote:

Hi,

The following is a proposal for a very minor extension of the @available system. Hopefully uncontroversial!

Thanks,

-Graydon

# Availability by Swift version

* Proposal: [SE-NNNN](NNNN-available-by-swift-version.md)
* Authors: [Graydon Hoare](https://github.com/graydon\)
* Review Manager: TBD
* Status: **Awaiting review**

## Introduction

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.

## Motivation

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.

## Proposed solution

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.

## Detailed design

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 effective `swift` 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, adding `swift` 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.

## Impact on existing code

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.

## Alternatives considered

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.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I am +1 on providing this facility but I am concerned that there are
several kinds of library evolutions, which we know we'll need for the
standard library, that it doesn't support.

One example is our plan to inject a new base protocol of Comparable that
will henceforth be known as Comparable (to support the <=> proposal).
Another thing we think we'll need to do is to turn what was one type in
Swift 3 into two distinct types in Swift 4. And these are just the
needs we can anticipate at this early stage. I am concerned that we
will need a system of much greater power and flexibility in the long
term.

···

on Thu Sep 22 2016, Graydon Hoare <swift-evolution@swift.org> wrote:

Hi,

The following is a proposal for a very minor extension of the @available system. Hopefully uncontroversial!

Thanks,

-Graydon

# Availability by Swift version

* Proposal: [SE-NNNN](NNNN-available-by-swift-version.md)
* Authors: [Graydon Hoare](https://github.com/graydon\)
* Review Manager: TBD
* Status: **Awaiting review**

## Introduction

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.

## Motivation

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.

## Proposed solution

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.

## Detailed design

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 effective `swift` 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, adding `swift` 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.

## Impact on existing code

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.

## Alternatives considered

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.

--
-Dave