Skip to content

Commit 7ed48ee

Browse files
authored
Merge pull request #1689 from lorentey/se-0358-remove-OptionSet-pat
[SE-0358] Remove OptionSet's primary annotation, deemphasize guidelines
2 parents 37d1c80 + e21015f commit 7ed48ee

File tree

1 file changed

+29
-21
lines changed

1 file changed

+29
-21
lines changed

proposals/0358-primary-associated-types-in-stdlib.md

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Proposal: [SE-0358](0358-primary-associated-types-in-stdlib.md)
44
* Authors: [Karoy Lorentey](https://github.com/lorentey)
55
* Review Manager: [John McCall](https://github.com/rjmccall)
6-
* Status: **Active review (May 18...June 20, 2022)**
6+
* Status: **Active review (May 18...June 27, 2022)**
77
* Implementation: [apple/swift#41843](https://github.com/apple/swift/pull/41843)
88
* Review: ([pitch](https://forums.swift.org/t/pitch-primary-associated-types-in-the-standard-library/56426/)) ([review](https://forums.swift.org/t/se-0358-primary-associated-types-in-the-standard-library/57432)) ([partial acceptance](https://forums.swift.org/t/se-0358-primary-associated-types-in-the-standard-library/57432/14))
99
* Related Proposals:
@@ -19,19 +19,21 @@
1919

2020
## Motivation
2121

22-
In order for the lightweight same-type requirement syntax introduced in [SE-0346] to be actually usable, protocol definitions inside and outside the Standard Library need to be extended with primary associated type declarations.
22+
In order for the lightweight constraint syntax introduced in [SE-0346] to be actually usable, protocol definitions inside and outside the Standard Library need to be extended with primary associated type declarations.
2323

2424
See [SE-0346] for several motivating examples for these changes.
2525

26-
## General API Design Guidelines
27-
28-
(The contents of this section are to be integrated into the Swift API Design Guidelines document, introduced in [SE-0023].)
26+
## API Design Guidelines
2927

3028
Primary associated types add a new facet to the design of protocols. For every public protocol with associated type requirements, we need to carefully consider which of them (if any) we want to mark as primary. On the one hand, we want to allow people to use the shorthand syntax whenever possible; on the other hand, we only get one chance to decide this: once a protocol gains a primary associated type annotation, most subsequent changes would be source-breaking.
3129

30+
We've found the following guidelines helpful when considering the adoption of primary associated types within the Standard Library. We haven't had enough real-life experience with this new feature to propose these guidelines for general use -- however, the recommendations below can still serve as a useful starting point.
31+
32+
(Aside: If you decide to follow these guidelines when annotating your own protocols, and they lead you to a choice that you later regret, please post a note on the Swift forums! Negative examples are going to be extremely helpful while revising the guidelines for general use. We're also looking for (positive or negative) examples for multiple primary associated types on a single protocol.)
33+
3234
1. **Let usage inform your design.**
3335

34-
If you are considering adding a primary associated type declaration to a preexisting protocol, then look at its existing clients to discover which associated types get typically mentioned in same-type requirements. Is there one particular type that is used overwhelmingly more than any other? If so, then it will probably be a good choice for the primary.
36+
If you are considering adding a primary associated type declaration to a preexisting protocol, then look at its existing clients to discover which associated types get typically constrained. Is there one particular type that is used overwhelmingly more than any other? If so, then it will probably be a good choice for the primary.
3537

3638
For example, in the case of `Sequence`, use sites overwhelmingly tend to constrain `Element` -- `Iterator` is almost never mentioned in `where` clauses. This makes it fairly clear that `Element` is the right choice for the primary type.
3739

@@ -41,7 +43,7 @@ Primary associated types add a new facet to the design of protocols. For every p
4143

4244
2. **Consider clarity at the point of use.** To prevent persistent confusion, _people familiar with the protocol_ ought to be able to correctly intuit the meaning of a same-type constraint such as `some Sequence<Int>`.
4345

44-
Lightweight same-type requirements share the same angle-bracketed syntax as generic type arguments, including the same limitations. In particular, the language does not support argument labels in such lists, which prevents us from clarifying the role of the type names provided. A type name such as `Foo<Int, String>` on its own provides no hints about the role of its generic arguments `Int` and `String`; likewise, it isn't possible to decipher the role of `Character` in a same-type requirement such as `some Bar<Character>`, unless the reader is already somewhat familiar with the protocol `Bar`.
46+
Lightweight constraint specifications share the same angle-bracketed syntax as generic type arguments, including the same limitations. In particular, the language does not support argument labels in such lists, which prevents us from clarifying the role of the type names provided. A type name such as `Foo<Int, String>` on its own provides no hints about the role of its generic arguments `Int` and `String`; likewise, it isn't possible to decipher the role of `Character` in a same-type requirement such as `some Bar<Character>`, unless the reader is already somewhat familiar with the protocol `Bar`.
4547

4648
The best candidates for primary associated types tend to be those that have a simple, obvious relationship to the protocol itself. A good heuristic is that if the relationship can be described using a simple preposition, then the associated type will probably make a viable primary:
4749

@@ -52,9 +54,9 @@ Primary associated types add a new facet to the design of protocols. For every p
5254

5355
Associated types that don't support this tend to have a more complex / idiosyncratic role in their protocol, and often make poor choices for a primary associated type.
5456

55-
For example, `Numeric` has an associated type called `Magnitude` that does sometimes appear in same-type constraints. However, its role seems too subtle and non-obvious to consider marking it as primary. The meaning of `Int` in `some Numeric<Int>` is unlikely to be clear to readers, even if they are deeply familiar with Swift's numeric protocol hierarchy.
57+
For example, `Numeric` has an associated type called `Magnitude` that does sometimes appear in associated type constraints. However, its role seems too subtle and non-obvious to consider marking it as primary. The meaning of `Int` in `some Numeric<Int>` is unlikely to be clear to readers, even if they are deeply familiar with Swift's numeric protocol hierarchy.
5658

57-
3. **Not every protocol needs primary associated types.** Don't feel obligated to add a primary associated type just because it is possible to do so. If you don't expect people will want to put same-type constraints on a type, there is little reason to mark it as a primary. Similarly, if there are multiple possible choices that seem equally useful, it might be best not to select one. (See point 2 above.)
59+
3. **Not every protocol needs primary associated types.** Don't feel obligated to add a primary associated type just because it is possible to do so. If you don't expect people will want to constrain an associated type in practice, there is little reason to mark it as a primary. Similarly, if there are multiple possible choices that seem equally useful, it might be best not to select one. (See point 2 above.)
5860

5961
For example, `ExpressibleByIntegerLiteral` is not expected to be mentioned in generic function declarations, so there is no reason to mark its sole associated type (`IntegerLiteral`) as the primary.
6062

@@ -103,7 +105,7 @@ The table below lists all public protocols in the Standard Library with associat
103105
| `RangeExpression` | `Bound` | -- |
104106
| `Strideable` | `Stride` | -- |
105107
| `SetAlgebra` | `Element` | `ArrayLiteralElement` |
106-
| `OptionSet` | `Element` | `ArrayLiteralElement`, `RawValue` |
108+
| `OptionSet` | -- [(2)][note] | `Element`, `ArrayLiteralElement`, `RawValue` |
107109
| `Numeric` | -- | `IntegerLiteralType`, `Magnitude` |
108110
| `SignedNumeric` | -- | `IntegerLiteralType`, `Magnitude` |
109111
| `BinaryInteger` | -- | `IntegerLiteralType`, `Magnitude`, `Stride`, `Words` |
@@ -134,14 +136,14 @@ The table below lists all public protocols in the Standard Library with associat
134136
| `CaseIterable` | -- | `AllCases` |
135137
| `Clock` | `Duration` | `Instant` |
136138
| `InstantProtocol` | `Duration` | -- |
137-
| `AsyncIteratorProtocol` | -- [(2)][note] | `Element` |
138-
| `AsyncSequence` | -- [(2)][note] | `AsyncIterator`, `Element` |
139+
| `AsyncIteratorProtocol` | -- [(3)][note] | `Element` |
140+
| `AsyncSequence` | -- [(3)][note] | `AsyncIterator`, `Element` |
139141
| `GlobalActor` | -- | `ActorType` |
140-
| `DistributedActor` | -- [(3)][note] | `ID`, `ActorSystem`, `SerializationRequirement` |
141-
| `DistributedActorSystem` | -- [(3)][note] | `ActorID`, `SerializationRequirement`, `InvocationEncoder`, `InvocationDecoder`, `ResultHandler` |
142-
| `DistributedTargetInvocationEncoder` | -- [(3)][note] | `SerializationRequirement` |
143-
| `DistributedTargetInvocationDecoder` | -- [(3)][note] | `SerializationRequirement` |
144-
| `DistributedTargetInvocationResultHandler` | -- [(3)][note] | `SerializationRequirement` |
142+
| `DistributedActor` | -- [(4)][note] | `ID`, `ActorSystem`, `SerializationRequirement` |
143+
| `DistributedActorSystem` | -- [(4)][note] | `ActorID`, `SerializationRequirement`, `InvocationEncoder`, `InvocationDecoder`, `ResultHandler` |
144+
| `DistributedTargetInvocationEncoder` | -- [(4)][note] | `SerializationRequirement` |
145+
| `DistributedTargetInvocationDecoder` | -- [(4)][note] | `SerializationRequirement` |
146+
| `DistributedTargetInvocationResultHandler` | -- [(4)][note] | `SerializationRequirement` |
145147

146148
As of Swift 5.6, the following public protocols don't have associated type requirements, so they are outside of the scope of this proposal.
147149

@@ -175,7 +177,6 @@ public protocol RangeExpression<Bound>
175177
public protocol Strideable<Stride>: Comparable
176178

177179
public prococol SetAlgebra<Element>: Equatable, ExpressibleByArrayLiteral
178-
public protocol OptionSet<Element>: SetAlgebra, RawRepresentable
179180

180181
public protocol SIMD<Scalar>: ...
181182

@@ -201,10 +202,17 @@ Therefore, we will not be able to make any changes to the list of primary associ
201202

202203
## Alternatives considered
203204

204-
(1) It is tempting to declare `Element` as the primary associated type for `LazySequenceProtocol` and `LazyCollectionProtocol`, for consistency with other protocols in the collection hierarchy. However, in actual use, `Elements` seems just as useful (if not more) to be easily constrained. We left the matter of selecting one of these as primary unresolved for now; as we get more experience with lightweight same-type requirements, we may revisit these protocols.
205+
(1) It is tempting to declare `Element` as the primary associated type for `LazySequenceProtocol` and `LazyCollectionProtocol`, for consistency with other protocols in the collection hierarchy. However, in actual use, `Elements` seems just as useful (if not more) to be easily constrained. We left the matter of selecting one of these as primary unresolved for now; as we get more experience with the lightweight constraint syntax, we may revisit these protocols.
205206

206-
(2) `AsyncSequence` and `AsyncIteratorProtocol` logically ought to have `Element` as their primary associated type. However, we have [ongoing evolution discussions][rethrows] about adding a precise error type to these. If those discussions bear fruit, then it's possible we may want to _also_ mark the potential new `Error` associated type as primary. To prevent source compatibility complications, adding primary associated types to these two protocols is deferred to a future proposal.
207+
(2) In the `OptionSet` protocol, the `Element` type is designed to always be `Self`, so `RawValue` would be the most practical choice for the primary associated type. However, to avoid potential confusion, we left `OptionSet` without a primary associated type annotation.
208+
209+
(3) `AsyncSequence` and `AsyncIteratorProtocol` logically ought to have `Element` as their primary associated type. However, we have [ongoing evolution discussions][rethrows] about adding a precise error type to these. If those discussions bear fruit, then it's possible we may want to _also_ mark the potential new `Error` associated type as primary. To prevent source compatibility complications, adding primary associated types to these two protocols is deferred to a future proposal.
207210

208211
[rethrows]: https://forums.swift.org/t/se-0346-lightweight-same-type-requirements-for-primary-associated-types/55869/70
209212

210-
(3) Declaring primary associated types on the distributed actor protocols would be desirable, but it was [deferred to a future proposal](https://forums.swift.org/t/pitch-primary-associated-types-in-the-standard-library/56426/47), to prevent interfering with potential future language improvements that would make them more useful in this use case.
213+
(4) Declaring primary associated types on the distributed actor protocols would be desirable, but it was [deferred to a future proposal](https://forums.swift.org/t/pitch-primary-associated-types-in-the-standard-library/56426/47), to prevent interfering with potential future language improvements that would make them more useful in this use case.
214+
215+
## Revisions
216+
217+
- [2022-05-28](https://github.com/apple/swift-evolution/blob/716db41ccefde348ac38bd2fd1eb5bd7842be7b6/proposals/0358-primary-associated-types-in-stdlib.md): Initial proposal version.
218+
- 2022-06-22: Removed the primary associated type declaration from the `OptionSet` protocol. The API guidelines section has revised wording; it no longer proposes the new guidelines for inclusion in the official Swift API Guidelines document. Adjusted wording to prefer the term "lightweight constraint syntax" to "lightweight same-type requirements", as the new syntax can be used for more than just to express same-type constraints.

0 commit comments

Comments
 (0)