Skip to content

Commit a4e4e8c

Browse files
kavonairspeedswift
andauthored
SE-427 updates to begin Round 2 of review (#2490)
* "accomodate" -> "accommodate" * require spelling out Copyable conditional requirements * subset out suppressed associatedtypes * Update 0427-noncopyable-generics.md --------- Co-authored-by: Ben Cohen <[email protected]>
1 parent 1e6a590 commit a4e4e8c

File tree

1 file changed

+87
-69
lines changed

1 file changed

+87
-69
lines changed

proposals/0427-noncopyable-generics.md

Lines changed: 87 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
* Proposal: [SE-0427](0427-noncopyable-generics.md)
44
* Authors: [Kavon Farvardin](https://github.com/kavon), [Tim Kientzle](https://github.com/tbkka), [Slava Pestov](https://github.com/slavapestov)
5-
* Review Manager: [Holly Borla](https://github.com/hborla)
6-
* Status: **Active Review (March 8 - March 22, 2024)**
5+
* Review Manager: [Holly Borla](https://github.com/hborla), [Ben Cohen](https://github.com/airspeedswift)
6+
* Status: **Active Review (July 1 - July 10, 2024)**
77
* Implementation: On `main` gated behind `-enable-experimental-feature NoncopyableGenerics`
88
* Previous Proposal: [SE-0390: Noncopyable structs and enums](0390-noncopyable-structs-and-enums.md)
9-
* Review: ([pitch](https://forums.swift.org/t/pitch-noncopyable-generics/68180))
9+
* Review: ([pitch](https://forums.swift.org/t/pitch-noncopyable-generics/68180)) ([first review](https://forums.swift.org/t/se-0427-noncopyable-generics/70525))
1010

1111
<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc -->
1212
**Table of Contents**
@@ -23,7 +23,6 @@
2323
- [Default conformances and suppression](#default-conformances-and-suppression)
2424
- [Struct, enum and class extensions](#struct-enum-and-class-extensions)
2525
- [Protocol extensions](#protocol-extensions)
26-
- [Associated types](#associated-types)
2726
- [Protocol inheritance](#protocol-inheritance)
2827
- [Conformance to `Copyable`](#conformance-to-copyable)
2928
- [Classes](#classes)
@@ -32,11 +31,13 @@
3231
- [ABI Compatibility](#abi-compatibility)
3332
- [Alternatives Considered](#alternatives-considered)
3433
- [Alternative spellings](#alternative-spellings)
34+
- [Associated types without defaulting behavior](#associated-types-without-defaulting-behavior)
3535
- [Inferred conditional copyability](#inferred-conditional-copyability)
3636
- [Extension defaults](#extension-defaults)
3737
- [Recursive `Copyable`](#recursive-copyable)
3838
- [`~Copyable` as logical negation](#copyable-as-logical-negation)
3939
- [Future Directions](#future-directions)
40+
- [Suppressed associated types](#suppressed-associated-types)
4041
- [Standard library adoption](#standard-library-adoption)
4142
- [Tuples and parameter packs](#tuples-and-parameter-packs)
4243
- [`~Escapable`](#escapable)
@@ -81,7 +82,7 @@ We begin by recalling the restrictions from SE-0390:
8182

8283
1. A noncopyable type could not appear in the generic argument of some other generic type.
8384
2. A noncopyable type could not conform to protocols.
84-
3. A noncopyable type could not witness an associated type requirement.
85+
3. A noncopyable type could not be boxed as an existential.
8586

8687
This proposal builds on the `~Copyable` notation introduced in SE-0390, and
8788
introduces three fundamental concepts that together eliminate these
@@ -205,7 +206,7 @@ unless explicitly suppressed:
205206
1. A struct, enum or class declaration.
206207
2. A generic parameter declaration.
207208
3. A protocol declaration.
208-
4. An associated type declaration.
209+
4. An associated type declaration; does not support suppression (see Future Directions).
209210
5. The `Self` type of a protocol extension.
210211
6. The generic parameters of a concrete extension.
211212

@@ -296,7 +297,7 @@ extension Horse where Hay: ~Copyable {...} // error
296297
### Protocol extensions
297298

298299
Where possible, we wish to allow the user to change an existing protocol to
299-
accomodate noncopyable conforming types, without changing the meaning of existing
300+
accommodate noncopyable conforming types, without changing the meaning of existing
300301
code.
301302

302303
For this reason, an extension of a `~Copyable` protocol also introduces a default
@@ -314,47 +315,14 @@ extension EventLog /* where Self: Copyable */ {
314315
}
315316
```
316317

317-
To write a completely unconstrained protocol extension, suppress the conformance
318-
on `Self`:
318+
To write an unconstrained protocol extension, suppress the conformance on `Self`:
319319
```swift
320320
extension EventLog where Self: ~Copyable {
321321
...
322322
}
323323
```
324-
325-
### Associated types
326-
327-
The default conformance in a protocol extension applies only to `Self`, and not
328-
the associated types of `Self`. For example, we first declare a protocol with a
329-
`~Copyable` associated type:
330-
```swift
331-
protocol Manager {
332-
associatedtype Resource: ~Copyable
333-
}
334-
```
335-
Now, a protocol extension of `Manager` does _not_ carry an implicit
336-
`Self.Resource: Copyable` requirement:
337-
```swift
338-
extension Manager {
339-
func f(resource: Resource) {
340-
// `resource' cannot be copied here!
341-
}
342-
}
343-
```
344-
For this reason, while adding `~Copyable` to the inheritance clause of a protocol
345-
is a source-compatible change, the same with an _associated type_ is not
346-
source compatible. The designer of a new protocol must decide which associated
347-
types are `~Copyable` up-front.
348-
349-
Requirements on associated types can be written in the associated type's
350-
inheritance clause, or in a `where` clause, or on the protocol itself. As
351-
with ordinary requirements, all three of the following forms define the same
352-
protocol:
353-
```swift
354-
protocol P { associatedtype A: ~Copyable }
355-
protocol P { associatedtype A where A: ~Copyable }
356-
protocol P where A: ~Copyable { associatedtype A }
357-
```
324+
Associated types cannot have their `Copyable` requirement suppressed
325+
(see Future Directions).
358326

359327
### Protocol inheritance
360328

@@ -368,22 +336,6 @@ protocol CasinoToken: Token, ~Copyable {}
368336
Again, because `~Copyable` suppresses a default conformance instead of introducing
369337
a new kind of requirement, it is not propagated through protocol inheritance.
370338

371-
If a base protocol declares an associated type with a suppressed conformance
372-
to `Copyable`, and a derived protocol re-states the associated type, a
373-
default conformance is introduced in the derived protocol, unless it is again
374-
suppressed:
375-
```swift
376-
protocol Base {
377-
associatedtype A: ~Copyable
378-
func f() -> A
379-
}
380-
381-
protocol Derived: Base {
382-
associatedtype A /* : Copyable */
383-
func g() -> A
384-
}
385-
```
386-
387339
### Conformance to `Copyable`
388340

389341
Structs and enums conform to `Copyable` unconditionally by default, but a
@@ -399,11 +351,11 @@ We would like `List<Int>` to be `Copyable` since `Int` is, while still being
399351
able to use a noncopyable element type, like `List<FileDescriptor>`. We do
400352
this by declaring a _conditional conformance_:
401353
```swift
402-
extension List: Copyable /* where T: Copyable */ {}
354+
extension List: Copyable where T: Copyable {}
403355
```
404-
Note that no `where` clause needs to be written, because by the rules above,
405-
the default conformances here will already range over all generic parameters
406-
of the type.
356+
Note that the `where` clause needs to be written, because a conformance to
357+
`Copyable` declared in an extension does _not_ automatically add any other
358+
requirements, unlike other extensions.
407359

408360
A conditional `Copyable` conformance is not permitted if the
409361
struct or enum declares a `deinit`. Deterministic destruction requires the
@@ -448,11 +400,6 @@ not permitted to make `Copyable` conditional on any other kind of requirement:
448400
```swift
449401
extension Pair: Copyable where T == Array<Int> {} // error
450402
```
451-
Nor can `Copyable` be conditional on the copyability of an associated type:
452-
```swift
453-
struct ManagerManager<T: Manager>: ~Copyable {}
454-
extension ManagerManager: Copyable where T.Resource: Copyable {} // error
455-
```
456403

457404
Conditional `Copyable` conformance must be declared in the same source
458405
file as the struct or enum itself. Unlike conformance to other protocols,
@@ -528,6 +475,69 @@ require extreme care to use correctly.
528475
The spelling of `~Copyable` generalizes the existing syntax introduced in
529476
SE-0390, and changing it is out of scope for this proposal.
530477

478+
### Associated types without defaulting behavior
479+
480+
A simple design for suppressed associated types was considered, where the
481+
default conformance in a protocol extension applies only to `Self`, and not
482+
the associated types of `Self`. For example, we first declare a protocol with a
483+
`~Copyable` associated type:
484+
```swift
485+
protocol Manager {
486+
associatedtype Resource: ~Copyable
487+
}
488+
```
489+
Now, a protocol extension of `Manager` does _not_ carry an implicit
490+
`Self.Resource: Copyable` requirement:
491+
```swift
492+
extension Manager {
493+
func f(resource: Resource) {
494+
// `resource' cannot be copied here!
495+
}
496+
}
497+
```
498+
For this reason, while adding `~Copyable` to the inheritance clause of a protocol
499+
is a source-compatible change, the same with an _associated type_ is not
500+
source compatible. The designer of a new protocol must decide which associated
501+
types are `~Copyable` up-front.
502+
503+
Requirements on associated types can be written in the associated type's
504+
inheritance clause, or in a `where` clause, or on the protocol itself. As
505+
with ordinary requirements, all three of the following forms define the same
506+
protocol:
507+
```swift
508+
protocol P { associatedtype A: ~Copyable }
509+
protocol P { associatedtype A where A: ~Copyable }
510+
protocol P where A: ~Copyable { associatedtype A }
511+
```
512+
513+
If a base protocol declares an associated type with a suppressed conformance
514+
to `Copyable`, and a derived protocol re-states the associated type, a
515+
default conformance is introduced in the derived protocol, unless it is again
516+
suppressed:
517+
```swift
518+
protocol Base {
519+
associatedtype A: ~Copyable
520+
func f() -> A
521+
}
522+
523+
protocol Derived: Base {
524+
associatedtype A /* : Copyable */
525+
func g() -> A
526+
}
527+
```
528+
529+
Finally, conformance to `Copyable` cannot be conditional on the copyability of
530+
an associated type:
531+
```swift
532+
struct ManagerManager<T: Manager>: ~Copyable {}
533+
extension ManagerManager: Copyable where T.Resource: Copyable {} // error
534+
```
535+
536+
This design for associated types was initially implemented but ultimately
537+
removed from this proposal, because of the source compatibility issues. A more
538+
comprehensive design that allows for some way of preserving source compatibility
539+
requires a separate proposal due to the open design issues.
540+
531541
### Inferred conditional copyability
532542

533543
A struct or enum can opt out of copyability with `~Copyable`, and then possibly
@@ -594,7 +604,7 @@ The behavior of default `Copyable` conformance on associated types prevents
594604
existing protocols from adopting `~Copyable` on their associated types in a
595605
source compatible way.
596606

597-
For example, suppose we attempt to change `IteratorProtocol` to accomodate
607+
For example, suppose we attempt to change `IteratorProtocol` to accommodate
598608
noncopyable element types:
599609
```swift
600610
protocol IteratorProtocol: ~Copyable {
@@ -657,6 +667,14 @@ usable model and we have not explored this further.
657667

658668
## Future Directions
659669

670+
### Suppressed associated types
671+
672+
Supporting the full generality of associated types with suppressed Copyable
673+
requirements, while providing a mechanism to preserve source compatibility is
674+
a highly desirable goal. At the same time, it is a large, open design problem.
675+
A few ideas were considered (see Alternatives Considered) but it was ultimately
676+
determined to be too complex to tackle in this proposal.
677+
660678
### Standard library adoption
661679

662680
The `Optional` and `UnsafePointer` family of types can support noncopyable types

0 commit comments

Comments
 (0)