From b5c54019427810f593d10566282946fbace649b8 Mon Sep 17 00:00:00 2001 From: Alex Martini Date: Tue, 9 Apr 2024 15:46:38 -0700 Subject: [PATCH 01/16] Start outlining discussion of noncopyable types --- TSPL.docc/LanguageGuide/Generics.md | 12 +++++++ TSPL.docc/LanguageGuide/Protocols.md | 54 ++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/TSPL.docc/LanguageGuide/Generics.md b/TSPL.docc/LanguageGuide/Generics.md index f446b72a1..6c2918fe7 100644 --- a/TSPL.docc/LanguageGuide/Generics.md +++ b/TSPL.docc/LanguageGuide/Generics.md @@ -618,6 +618,18 @@ that requires `T` to be a subclass of `SomeClass`. The second type parameter, `U`, has a type constraint that requires `U` to conform to the protocol `SomeProtocol`. + + ### Type Constraints in Action Here's a nongeneric function called `findIndex(ofString:in:)`, diff --git a/TSPL.docc/LanguageGuide/Protocols.md b/TSPL.docc/LanguageGuide/Protocols.md index 1bc0d29d4..1c5a92c5f 100644 --- a/TSPL.docc/LanguageGuide/Protocols.md +++ b/TSPL.docc/LanguageGuide/Protocols.md @@ -752,6 +752,24 @@ a nonfailable initializer or an implicitly unwrapped failable initializer. ``` --> +## Protocols Without Requirements + + + ## Protocols as Types Protocols don't actually implement any functionality themselves. @@ -1368,6 +1386,42 @@ for level in levels.sorted() { ``` --> +## Implicit Conformance to a Protocol + + + ## Collections of Protocol Types A protocol can be used as the type to be stored in From 2175495e08e4513dda41889dd1bbf74bf4729e43 Mon Sep 17 00:00:00 2001 From: Alex Martini Date: Fri, 12 Apr 2024 16:26:36 -0700 Subject: [PATCH 02/16] Add note about passing noncopyable values as arguments --- TSPL.docc/ReferenceManual/Declarations.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/TSPL.docc/ReferenceManual/Declarations.md b/TSPL.docc/ReferenceManual/Declarations.md index 57c781366..f343df11c 100644 --- a/TSPL.docc/ReferenceManual/Declarations.md +++ b/TSPL.docc/ReferenceManual/Declarations.md @@ -1070,6 +1070,8 @@ if you want more specific control, you can apply the `borrowing` or `consuming` parameter modifier. In this case, use `copy` to explicitly mark copy operations. +In addition, +values of a noncopyable type must be passed as either borrowing or consuming. Regardless of whether you use the default rules, Swift guarantees that object lifetime and From f055bc13384ac62436d35c7e5b0b08eed17be13c Mon Sep 17 00:00:00 2001 From: Alex Martini Date: Tue, 14 May 2024 17:05:29 -0700 Subject: [PATCH 03/16] Sketch discussion of the ~Copyable syntax --- TSPL.docc/LanguageGuide/Generics.md | 49 +++++++++++++++++++++------- TSPL.docc/LanguageGuide/Protocols.md | 2 +- 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/TSPL.docc/LanguageGuide/Generics.md b/TSPL.docc/LanguageGuide/Generics.md index 6c2918fe7..7b2119c63 100644 --- a/TSPL.docc/LanguageGuide/Generics.md +++ b/TSPL.docc/LanguageGuide/Generics.md @@ -618,18 +618,6 @@ that requires `T` to be a subclass of `SomeClass`. The second type parameter, `U`, has a type constraint that requires `U` to conform to the protocol `SomeProtocol`. - - ### Type Constraints in Action Here's a nongeneric function called `findIndex(ofString:in:)`, @@ -1967,6 +1955,43 @@ Taken together, these constraints mean that the value passed for the `indices` parameter is a sequence of integers. +## Implicit Constraints + +In addition to the constraints you write explicitly, +many places in your code +also implicitly include an constraint +that types conform to the `Copyable` protocol. +This constraint is implicit because almost all types in Swift are copyable, +so you only have to specify when something shouldn't be copyable. +For example, both of the following function declarations +require `T` to be copyable: + +``` +function someFunction { ... } +function someFunction { ... } +``` + +To suppress an implicit conformance to `Copyable` +you write the protocol name with a tilde (`~`) in front of it. +You can read `~Copyable` as "maybe copyable", +because can can contain values of both copyable an noncopyable types. + +``` +func f(t: inout T) { + let t1 = t // The value of 't' is copyied into 't1' + let t2 = t // The value of 't' is copyied into 't2' +} + +func g(t: inout T) { + let t1 = t // The value of 't' is consumed by 't1' + let t2 = t // Error: 't' consumed more than once +} +``` + +XXX +noncopyable values must be passed as in-out, borrowing, or consuming +xref reference > Declarations > Borrowing and Consuming Parameters + -## Protocols Without Requirements +## Protocols That Don't Have Requirements ## Collections of Protocol Types From c3a494257c75259318d3ff0a3e8dc1f6643b1a51 Mon Sep 17 00:00:00 2001 From: Alex Martini Date: Thu, 16 Jan 2025 16:41:32 -0800 Subject: [PATCH 05/16] Expand the outline for ~Foo syntax --- TSPL.docc/LanguageGuide/Generics.md | 2 + TSPL.docc/LanguageGuide/Protocols.md | 107 ++++++++++++++++++--------- 2 files changed, 74 insertions(+), 35 deletions(-) diff --git a/TSPL.docc/LanguageGuide/Generics.md b/TSPL.docc/LanguageGuide/Generics.md index 7b2119c63..36d276b24 100644 --- a/TSPL.docc/LanguageGuide/Generics.md +++ b/TSPL.docc/LanguageGuide/Generics.md @@ -1992,6 +1992,8 @@ XXX noncopyable values must be passed as in-out, borrowing, or consuming xref reference > Declarations > Borrowing and Consuming Parameters +XXX xref Protocols > Implicit Conformance + +The Swift standard library defines several protocols +that don't have any required methods or properties: -- `Copyable` -- `Sendable` -- `BitwiseCopyable` +- `Copyable` for values that can be copied. +- `Sendable` for values that can be shared across concurrency contexts. +- `BitwiseCopyable` for values that con be copied, bit-by-bit. + + +For more information about the semantic requirements, +see the protocols' documentation. + +You use the same syntax as usual to adopt these protocols. +The only difference is that +there's no code to implement the protocol's requirements. -You conform to these as usual -- -just there’s nothing in the body, -because there aren’t any requirements to satisfy. +```swift +struct MyStruct: Copyable { + var counter = 12 +} +extension MyStruct: BitwiseCopyable { } ``` -extension struct MyStruct: Codable { } ---> + +The code above defines a new structure +Because `Copyable` has only semantic requirements, +there isn't any code in the structure declaration to adopt the protocol. +Likewise, because `BitwiseCopyable` has only semantic requirements, +the extension that adopts that protocol has an empty body. + +You usually don't need to write conformance to these protocols --- +instead, Swift implicitly adds the conformance for you, +as described in . + + ## Protocols as Types @@ -1388,44 +1415,54 @@ for level in levels.sorted() { ## Implicit Conformance to a Protocol - -``` -struct MyStruct: ~Codable { var someNumber: Int } +You can still write the conformance explicitly, +but it doesn't have any effect. +To suppress an implicit conformance, +write a tilde (`~`) before the protocol name in the conformance list: + +```swift +struct FileDescriptor: ~Copyable { + let rawValue: Int +} ``` -Writing `~Sendable` suppresses implicit sendability. -In contrast, -the following suppresses implicit conformance, -and also prevents you from conforming elsewhere: + -``` -@available(*, unavailable) extension X: Sendable {} -``` +The declaration of the `FileDescriptor` type above +satisfies all of the requirements of the `Copyable` protocol, +which would normally mean it's implicitly considered to be copyable. +However, +writing a conformance to `~Copyable` suppresses this implicit conformance. -This replaces the existing `@available(*, unavailable)` example from the Concurrency chapter for most use cases. +XXX conditional re-conformance after suppression -See also the comparison on this forum thread +Another way to suppress implicit conformance +is with an extension that you mark as unavailable: -XREF new section in Generics about `~Foo` syntax in a requirement. +```swift +@available(*, unavailable) +extension FileDescriptor Copyable { } +``` -Enums with no associated types are implicitly equatable and hashable. -(TR: And also sendable?) -This is an exception to the rule that public API -must be declared explicitly. ---> +This code not only suppresses the implicit conformance to `Copyable`, +but also prevents any extensions elsewhere in your code +from adding `Copyable` conformance to the type. + ## Collections of Protocol Types From c1fbb99f23eb855a0249d9b058f7a22729e70fb8 Mon Sep 17 00:00:00 2001 From: Alex Martini Date: Fri, 17 Jan 2025 18:12:06 -0800 Subject: [PATCH 06/16] Move in the ~P example from Concurrency. --- TSPL.docc/LanguageGuide/Concurrency.md | 45 +++++------------------ TSPL.docc/LanguageGuide/Protocols.md | 51 +++++++++++++++++++++----- 2 files changed, 51 insertions(+), 45 deletions(-) diff --git a/TSPL.docc/LanguageGuide/Concurrency.md b/TSPL.docc/LanguageGuide/Concurrency.md index 4cce85123..8b9464ee5 100644 --- a/TSPL.docc/LanguageGuide/Concurrency.md +++ b/TSPL.docc/LanguageGuide/Concurrency.md @@ -1322,52 +1322,25 @@ struct TemperatureReading { --> To explicitly mark a type as not being sendable, -overriding an implicit conformance to the `Sendable` protocol, -use an extension: +write `~Sendable` after the type: ```swift -struct FileDescriptor { - let rawValue: CInt +struct FileDescriptor: ~Sendable { + let rawValue: Int } - -@available(*, unavailable) -extension FileDescriptor: Sendable { } ``` - -The code above shows part of a wrapper around POSIX file descriptors. -Even though interface for file descriptors uses integers -to identify and interact with open files, -and integer values are sendable, -a file descriptor isn't safe to send across concurrency domains. - -In the code above, -the `FileDescriptor` is a structure -that meets the criteria to be implicitly sendable. -However, the extension makes its conformance to `Sendable` unavailable, -preventing the type from being sendable. +For more information about +suppressing an implicit conformance to a protocol, +see . -The declaration of the `FileDescriptor` type above -satisfies all of the requirements of the `Copyable` protocol, -which would normally mean it's implicitly considered to be copyable. +The code above shows part of a wrapper around POSIX file descriptors. +The `FileDescriptor` structure +satisfies all of the requirements of the `Sendable` protocol, +which would normally make it sendable. However, -writing a conformance to `~Copyable` suppresses this implicit conformance. +writing `~Sendable` suppresses this implicit conformance. + +Even though file descriptors use integers +to identify and interact with open files, +and integer values are sendable, +making it nonsendable can help avoid certain kinds of bugs. + + + +In the code above, +the `FileDescriptor` is a structure +that meets the criteria to be implicitly sendable. +However, the extension makes its conformance to `Sendable` unavailable, +preventing the type from being sendable. XXX conditional re-conformance after suppression @@ -1456,13 +1489,13 @@ is with an extension that you mark as unavailable: ```swift @available(*, unavailable) -extension FileDescriptor Copyable { } +extension FileDescriptor Sendable { } ``` -This code not only suppresses the implicit conformance to `Copyable`, +This code not only suppresses the implicit conformance to `Sendable`, but also prevents any extensions elsewhere in your code -from adding `Copyable` conformance to the type. - +from adding `Sendable` conformance to the type. + ## Collections of Protocol Types From ad21441bdd1b7bdf265bf0a38858bb51bfb4d320 Mon Sep 17 00:00:00 2001 From: Alex Martini Date: Fri, 24 Jan 2025 21:05:33 -0800 Subject: [PATCH 07/16] Fill in some placeholders; add others. --- TSPL.docc/LanguageGuide/Generics.md | 36 +++++++++++++++----- TSPL.docc/LanguageGuide/Protocols.md | 49 ++++++++++++++++++---------- 2 files changed, 58 insertions(+), 27 deletions(-) diff --git a/TSPL.docc/LanguageGuide/Generics.md b/TSPL.docc/LanguageGuide/Generics.md index 36d276b24..d5b936f5c 100644 --- a/TSPL.docc/LanguageGuide/Generics.md +++ b/TSPL.docc/LanguageGuide/Generics.md @@ -1958,26 +1958,41 @@ is a sequence of integers. ## Implicit Constraints In addition to the constraints you write explicitly, -many places in your code +many places in your code also implicitly include an constraint that types conform to the `Copyable` protocol. + This constraint is implicit because almost all types in Swift are copyable, so you only have to specify when something shouldn't be copyable. For example, both of the following function declarations -require `T` to be copyable: +require `MyType` to be copyable: +```swift +function someFunction { ... } +function someFunction { ... } ``` -function someFunction { ... } -function someFunction { ... } -``` + +XXX the constraint is implicit -- and so is satisfying it most of the time +For more information, +see . + To suppress an implicit conformance to `Copyable` +or an implicit `Copyable` requirement, you write the protocol name with a tilde (`~`) in front of it. You can read `~Copyable` as "maybe copyable", because can can contain values of both copyable an noncopyable types. -``` -func f(t: inout T) { +```swift +func f(t: inout MyType) { let t1 = t // The value of 't' is copyied into 't1' let t2 = t // The value of 't' is copyied into 't2' } @@ -1988,11 +2003,14 @@ func g(t: inout T) { } ``` +XXX where you can/can't suppress Copyable + +XXX xref stdlib reference for Copyable? + XXX noncopyable values must be passed as in-out, borrowing, or consuming xref reference > Declarations > Borrowing and Consuming Parameters - -XXX xref Protocols > Implicit Conformance +. - For more information about the semantic requirements, see the protocols' documentation. @@ -1423,9 +1431,18 @@ when you define a type that implements the protocol's requirements: - `Codable` - `Copyable` - `Sendable` -- `BitwiseCopyale` +- `BitwiseCopyable` - +[`Codable`]: https://developer.apple.com/documentation/swift/codable + + + You can still write the conformance explicitly, but it doesn't have any effect. @@ -1452,7 +1469,6 @@ satisfies all of the requirements of the `Sendable` protocol, which would normally make it sendable. However, writing `~Sendable` suppresses this implicit conformance. - Even though file descriptors use integers to identify and interact with open files, and integer values are sendable, @@ -1476,14 +1492,6 @@ making it nonsendable can help avoid certain kinds of bugs. !! ^ --> -In the code above, -the `FileDescriptor` is a structure -that meets the criteria to be implicitly sendable. -However, the extension makes its conformance to `Sendable` unavailable, -preventing the type from being sendable. - -XXX conditional re-conformance after suppression - Another way to suppress implicit conformance is with an extension that you mark as unavailable: @@ -1492,11 +1500,16 @@ is with an extension that you mark as unavailable: extension FileDescriptor Sendable { } ``` -This code not only suppresses the implicit conformance to `Sendable`, -but also prevents any extensions elsewhere in your code +When you write `~Sendable` in one place in your code, +as in the previous example, +code elsewhere in your program can still +extend the `FileDescriptor` type to add `Sendable` conformance. +In contrast, +the unavailable extension in this example +suppresses the implicit conformance to `Sendable` +and also prevents any extensions elsewhere in your code from adding `Sendable` conformance to the type. - ## Collections of Protocol Types A protocol can be used as the type to be stored in From b6439e7d207f2675f346310ea8a56e7e29ef1c10 Mon Sep 17 00:00:00 2001 From: Alex Martini Date: Mon, 27 Jan 2025 15:03:09 -0800 Subject: [PATCH 08/16] Fill in discussion of implicit constraints --- TSPL.docc/LanguageGuide/Generics.md | 72 +++++++++++++++------------- TSPL.docc/LanguageGuide/Protocols.md | 7 +-- 2 files changed, 42 insertions(+), 37 deletions(-) diff --git a/TSPL.docc/LanguageGuide/Generics.md b/TSPL.docc/LanguageGuide/Generics.md index d5b936f5c..6b214b3b6 100644 --- a/TSPL.docc/LanguageGuide/Generics.md +++ b/TSPL.docc/LanguageGuide/Generics.md @@ -1960,18 +1960,17 @@ is a sequence of integers. In addition to the constraints you write explicitly, many places in your code also implicitly include an constraint -that types conform to the `Copyable` protocol. - -This constraint is implicit because almost all types in Swift are copyable, -so you only have to specify when something shouldn't be copyable. +that types conform to some very common protocols +like [`Copyable`][]. + +For information on when a protocol is implied, +see the reference for that protocol. + +[`Copyable`]: https://developer.apple.com/documentation/swift/copyable + +This constraint is implicit because +almost all types in Swift conform to these protocols, +so you specify only the exceptions. For example, both of the following function declarations require `MyType` to be copyable: @@ -1980,37 +1979,46 @@ function someFunction { ... } function someFunction { ... } ``` -XXX the constraint is implicit -- and so is satisfying it most of the time +Both declarations of `someFunction()` in the code above +require the generic type parameter `MyType` to be copyable. +In the first version, the constraint is implicit; +the second version lists the explicitly. +In most code, +types also implicitly conform to these common protocol. For more information, see . - -To suppress an implicit conformance to `Copyable` -or an implicit `Copyable` requirement, +To suppress an implicit protocol conformance requirement, you write the protocol name with a tilde (`~`) in front of it. -You can read `~Copyable` as "maybe copyable", -because can can contain values of both copyable an noncopyable types. +You can read the `~Copyable` constraint as "maybe copyable", +because values of this type +can contain values of both copyable and noncopyable types. ```swift -func f(t: inout MyType) { - let t1 = t // The value of 't' is copyied into 't1' - let t2 = t // The value of 't' is copyied into 't2' +func f(x: inout MyType) { + let x1 = x // The value of x1 is a copy of x's value. + let x2 = x // The value of x2 is a copy of x's value. } -func g(t: inout T) { - let t1 = t // The value of 't' is consumed by 't1' - let t2 = t // Error: 't' consumed more than once +func g(y: inout AnotherType) { + let y1 = y // The assignment consumes y's value. + let y2 = y // Error: Value consumed more than once. } ``` -XXX where you can/can't suppress Copyable - -XXX xref stdlib reference for Copyable? - -XXX -noncopyable values must be passed as in-out, borrowing, or consuming -xref reference > Declarations > Borrowing and Consuming Parameters -. +In the code above, +the function `f()` implicitly requires `MyType` to be copyable. +Within the function body, +the value of `x` is copied to `x1` and `x2` in the assignment. +In contrast, `g()` suppresses the implicit requirement, +which allows you to pass either a copyable or noncopyable type. +Within the function body, +the value of `y` is consumed instead of copied, +and it's an error to consume that value more than once. +Noncopyable values like `y` +must be passed as in-out, borrowing, or consuming parameters --- +for more information, +see . - - You can still write the conformance explicitly, but it doesn't have any effect. To suppress an implicit conformance, @@ -1461,6 +1456,8 @@ https://github.com/apple/swift-system/blob/main/Sources/System/FileDescriptor.sw See also this PR that adds Sendable conformance to FileDescriptor: https://github.com/apple/swift-system/pull/112 + +XXX SE-0390 uses the same example but ~Copyable -- is that better? --> The code above shows part of a wrapper around POSIX file descriptors. From d9513a7a964513058c09afd94382d9815fc64520 Mon Sep 17 00:00:00 2001 From: Alex Martini Date: Mon, 27 Jan 2025 16:27:03 -0800 Subject: [PATCH 09/16] Fix placement of (inactive) swifttest comment --- TSPL.docc/LanguageGuide/Protocols.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/TSPL.docc/LanguageGuide/Protocols.md b/TSPL.docc/LanguageGuide/Protocols.md index 6a2660eaa..bbd4bbb35 100644 --- a/TSPL.docc/LanguageGuide/Protocols.md +++ b/TSPL.docc/LanguageGuide/Protocols.md @@ -1471,6 +1471,14 @@ to identify and interact with open files, and integer values are sendable, making it nonsendable can help avoid certain kinds of bugs. +Another way to suppress implicit conformance +is with an extension that you mark as unavailable: + +```swift +@available(*, unavailable) +extension FileDescriptor Sendable { } +``` + -Another way to suppress implicit conformance -is with an extension that you mark as unavailable: - -```swift -@available(*, unavailable) -extension FileDescriptor Sendable { } -``` - When you write `~Sendable` in one place in your code, as in the previous example, code elsewhere in your program can still From 567a78b123ada1b739cb41153a4ae0095c7163dc Mon Sep 17 00:00:00 2001 From: Alex Martini Date: Mon, 27 Jan 2025 16:33:27 -0800 Subject: [PATCH 10/16] Match terminology --- TSPL.docc/LanguageGuide/Generics.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/TSPL.docc/LanguageGuide/Generics.md b/TSPL.docc/LanguageGuide/Generics.md index e5cbe6eed..e72a70ead 100644 --- a/TSPL.docc/LanguageGuide/Generics.md +++ b/TSPL.docc/LanguageGuide/Generics.md @@ -1988,7 +1988,8 @@ types also implicitly conform to these common protocol. For more information, see . -To suppress an implicit protocol conformance requirement, +To suppress an implicit constraint +that requires conformance to a given protocol, you write the protocol name with a tilde (`~`) in front of it. You can read the `~Copyable` constraint as "maybe copyable", because values of this type @@ -2010,7 +2011,7 @@ In the code above, the function `f()` implicitly requires `MyType` to be copyable. Within the function body, the value of `x` is copied to `x1` and `x2` in the assignment. -In contrast, `g()` suppresses the implicit requirement, +In contrast, `g()` suppresses the implicit constraint, which allows you to pass either a copyable or noncopyable type. Within the function body, the value of `y` is consumed instead of copied, From 84d637290b2a11e6f122c728c23106e6e52a4b13 Mon Sep 17 00:00:00 2001 From: Alex Martini Date: Mon, 27 Jan 2025 16:42:07 -0800 Subject: [PATCH 11/16] Call out a tripping hazard & wordsmith a bit --- TSPL.docc/LanguageGuide/Generics.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/TSPL.docc/LanguageGuide/Generics.md b/TSPL.docc/LanguageGuide/Generics.md index e72a70ead..eb4e883d2 100644 --- a/TSPL.docc/LanguageGuide/Generics.md +++ b/TSPL.docc/LanguageGuide/Generics.md @@ -1988,12 +1988,13 @@ types also implicitly conform to these common protocol. For more information, see . -To suppress an implicit constraint -that requires conformance to a given protocol, +To suppress an implicit constraint, you write the protocol name with a tilde (`~`) in front of it. -You can read the `~Copyable` constraint as "maybe copyable", -because values of this type -can contain values of both copyable and noncopyable types. +You can read `~Copyable` as "maybe copyable" --- +this suppressed constraint allows +both copyable and noncopyable types in this position. +Note that `~Copyable` doesn't *require* the type to be noncopyable. +For example: ```swift func f(x: inout MyType) { @@ -2011,10 +2012,12 @@ In the code above, the function `f()` implicitly requires `MyType` to be copyable. Within the function body, the value of `x` is copied to `x1` and `x2` in the assignment. -In contrast, `g()` suppresses the implicit constraint, -which allows you to pass either a copyable or noncopyable type. +In contrast, `g()` suppresses the implicit constraint on `AnotherType`, +which allows you to pass either a copyable or noncopyable value. Within the function body, -the value of `y` is consumed instead of copied, +you can't copy the value of `y` +because `AnotherType` might be noncopyable. +Assignment consumes the value of `y` and it's an error to consume that value more than once. Noncopyable values like `y` must be passed as in-out, borrowing, or consuming parameters --- From 627acb34d8750a2a92ad7b8dd0554d86c0c5bb8a Mon Sep 17 00:00:00 2001 From: Alex Martini Date: Tue, 25 Feb 2025 16:03:33 -0800 Subject: [PATCH 12/16] Incorporate tech review Co-authored-by: Apollo Zhu Co-authored-by: Slava Pestov Co-authored-by: Xiaodi Wu --- TSPL.docc/LanguageGuide/Protocols.md | 58 +++++++++++++++++----------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/TSPL.docc/LanguageGuide/Protocols.md b/TSPL.docc/LanguageGuide/Protocols.md index bbd4bbb35..418eccb90 100644 --- a/TSPL.docc/LanguageGuide/Protocols.md +++ b/TSPL.docc/LanguageGuide/Protocols.md @@ -752,11 +752,14 @@ a nonfailable initializer or an implicitly unwrapped failable initializer. ``` --> -## Protocols That Don't Have Requirements +## Protocols That Have Semantic Requirements -All of the example protocols above have some requirements, +All of the example protocols above require some methods or properties, but a protocol doesn't have to include any requirements. -You can use a protocol to mark types that satisfy *semantic* requirements, +You can also use a protocol to mark types +that satisfy some *semantic* requirements --- +requirements about how values of those types behave +and about operations that they support --- not just requirements that you express in code. -For more information about the semantic requirements, -see the protocols' documentation. +For information about these protocols' requirements, +see the overview in their documentation. -You use the same syntax as usual to adopt these protocols. -The only difference is that -there's no code to implement the protocol's requirements. +You use the same syntax to adopt these protocols +as you do to adopt other protocols. +The only difference is that you don't include +method or property declarations that implement the protocol's requirements. +For example: ```swift struct MyStruct: Copyable { @@ -1423,24 +1431,24 @@ for level in levels.sorted() { ## Implicit Conformance to a Protocol -Some protocols are so common that you would write them on almost every type. +Some protocols are so common that you would write them +almost every time you declare a new type. For the following protocols, Swift automatically infers the conformance -when you define a type that implements the protocol's requirements: +when you define a type that implements the protocol's requirements, +so you don't have to write them yourself: -- `Codable` -- `Copyable` -- `Sendable` -- `BitwiseCopyable` +- [`Copyable`][] +- [`Sendable`][] +- [`BitwiseCopyable`][] -[`Codable`]: https://developer.apple.com/documentation/swift/codable You can still write the conformance explicitly, -but it doesn't have any effect. +but it doesn't change how your code behaves. To suppress an implicit conformance, write a tilde (`~`) before the protocol name in the conformance list: @@ -1507,6 +1515,12 @@ suppresses the implicit conformance to `Sendable` and also prevents any extensions elsewhere in your code from adding `Sendable` conformance to the type. +> Note: +> In addition to the protocols discussed above, +> distributed actors implicitly conform to the [`Codable`][] protocol. + +[`Codable`]: https://developer.apple.com/documentation/swift/codable + ## Collections of Protocol Types A protocol can be used as the type to be stored in From d6fee6549e9b1ed21dff76620c384d1b8e9d262b Mon Sep 17 00:00:00 2001 From: Alex Martini Date: Tue, 29 Apr 2025 20:14:29 -0700 Subject: [PATCH 13/16] All protocols (should) have semantic requirements Incorporates feedback from Xiaodi Wu . --- TSPL.docc/LanguageGuide/Protocols.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/TSPL.docc/LanguageGuide/Protocols.md b/TSPL.docc/LanguageGuide/Protocols.md index 418eccb90..8a37037d4 100644 --- a/TSPL.docc/LanguageGuide/Protocols.md +++ b/TSPL.docc/LanguageGuide/Protocols.md @@ -752,15 +752,13 @@ a nonfailable initializer or an implicitly unwrapped failable initializer. ``` --> -## Protocols That Have Semantic Requirements +## Protocols That Have Only Semantic Requirements All of the example protocols above require some methods or properties, -but a protocol doesn't have to include any requirements. -You can also use a protocol to mark types -that satisfy some *semantic* requirements --- -requirements about how values of those types behave -and about operations that they support --- -not just requirements that you express in code. +but a protocol declaration doesn't have to include any requirements. +You can also use a protocol to describe *semantic* requirements --- +that is, requirements about how values of those types behave +and about operations that they support. For information on when a protocol is implied, @@ -1968,7 +1968,7 @@ see the reference for that protocol. [`Copyable`]: https://developer.apple.com/documentation/swift/copyable -This constraint is implicit because +These constraints are implicit because almost all types in Swift conform to these protocols, so you specify only the exceptions. For example, both of the following function declarations @@ -1984,7 +1984,7 @@ require the generic type parameter `MyType` to be copyable. In the first version, the constraint is implicit; the second version lists the explicitly. In most code, -types also implicitly conform to these common protocol. +types also implicitly conform to these common protocols. For more information, see . diff --git a/TSPL.docc/LanguageGuide/OpaqueTypes.md b/TSPL.docc/LanguageGuide/OpaqueTypes.md index 1b271531d..6509bdf12 100644 --- a/TSPL.docc/LanguageGuide/OpaqueTypes.md +++ b/TSPL.docc/LanguageGuide/OpaqueTypes.md @@ -23,7 +23,7 @@ Boxed protocol types don't preserve type identity --- the value's specific type isn't known until runtime, and it can change over time as different values are stored. -## The Problem That Opaque Types Solve +## The Problem that Opaque Types Solve For example, suppose you're writing a module that draws ASCII art shapes. diff --git a/TSPL.docc/LanguageGuide/Protocols.md b/TSPL.docc/LanguageGuide/Protocols.md index 8a37037d4..8a43274af 100644 --- a/TSPL.docc/LanguageGuide/Protocols.md +++ b/TSPL.docc/LanguageGuide/Protocols.md @@ -752,7 +752,7 @@ a nonfailable initializer or an implicitly unwrapped failable initializer. ``` --> -## Protocols That Have Only Semantic Requirements +## Protocols that Have Only Semantic Requirements All of the example protocols above require some methods or properties, but a protocol declaration doesn't have to include any requirements. @@ -799,10 +799,10 @@ struct MyStruct: Copyable { extension MyStruct: BitwiseCopyable { } ``` -The code above defines a new structure +The code above defines a new structure. Because `Copyable` has only semantic requirements, there isn't any code in the structure declaration to adopt the protocol. -Likewise, because `BitwiseCopyable` has only semantic requirements, +Similarly, because `BitwiseCopyable` has only semantic requirements, the extension that adopts that protocol has an empty body. You usually don't need to write conformance to these protocols --- @@ -1469,7 +1469,7 @@ XXX SE-0390 uses the same example but ~Copyable -- is that better? The code above shows part of a wrapper around POSIX file descriptors. The `FileDescriptor` structure satisfies all of the requirements of the `Sendable` protocol, -which would normally make it sendable. +which normally makes it sendable. However, writing `~Sendable` suppresses this implicit conformance. Even though file descriptors use integers From 4e52796403f01fa769beb2ba4a31a74f9c421604 Mon Sep 17 00:00:00 2001 From: Alex Martini Date: Tue, 13 May 2025 19:38:07 -0700 Subject: [PATCH 15/16] Improve flow & re-adjust awkward wording --- TSPL.docc/LanguageGuide/Generics.md | 32 +++++++++++++++-------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/TSPL.docc/LanguageGuide/Generics.md b/TSPL.docc/LanguageGuide/Generics.md index d94970692..0d5a3bfbc 100644 --- a/TSPL.docc/LanguageGuide/Generics.md +++ b/TSPL.docc/LanguageGuide/Generics.md @@ -1957,23 +1957,17 @@ is a sequence of integers. ## Implicit Constraints -In addition to the constraints you write explicitly, -many places in your generic code -also include implicit constraints -that require types to conform to some very common protocols -like [`Copyable`][]. - -For information on when a protocol is implied, -see the reference for that protocol. - -[`Copyable`]: https://developer.apple.com/documentation/swift/copyable - -These constraints are implicit because -almost all types in Swift conform to these protocols, -so you specify only the exceptions. +In addition to constraints you write explicitly, +many places in your generic code also implicitly require +conformance to some very common protocols like [`Copyable`][]. + +These generic constraints that you don't have to write +are known as *implicit constraints*. For example, both of the following function declarations require `MyType` to be copyable: +[`Copyable`]: https://developer.apple.com/documentation/swift/copyable + ```swift function someFunction { ... } function someFunction { ... } @@ -1988,8 +1982,12 @@ types also implicitly conform to these common protocols. For more information, see . +Because most types in Swift conform to these protocols, +writing them almost everywhere would be repetitive. +Instead, by marking only the exceptions, +your call out the places that omit a common constraint. To suppress an implicit constraint, -you write the protocol name with a tilde (`~`) in front of it. +write the protocol name with a tilde (`~`) in front of it. You can read `~Copyable` as "maybe copyable" --- this suppressed constraint allows both copyable and noncopyable types in this position. @@ -2024,6 +2022,10 @@ must be passed as in-out, borrowing, or consuming parameters --- for more information, see . +For details about when generic code +includes an implicit constraint to a given protocol, +see the reference for that protocol. + + ## Protocols as Types @@ -1462,8 +1462,6 @@ https://github.com/apple/swift-system/blob/main/Sources/System/FileDescriptor.sw See also this PR that adds Sendable conformance to FileDescriptor: https://github.com/apple/swift-system/pull/112 - -XXX SE-0390 uses the same example but ~Copyable -- is that better? --> The code above shows part of a wrapper around POSIX file descriptors.