Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more existentials documentation #340

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion TSPL.docc/LanguageGuide/OpaqueTypes.md
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@ A boxed protocol type is also sometimes called an *existential type*,
which comes from the phrase
"there exists a type *T* such that *T* conforms to the protocol".
To make a boxed protocol type,
write `any` before the name of a protocol.
write `any` before the name of a protocol (or protocol composition).
Here's an example:

```swift
Expand Down Expand Up @@ -621,6 +621,29 @@ if let downcastTriangle = vertical.shapes[0] as? Triangle {

For more information, see <doc:TypeCasting#Downcasting>.

### Existential Of Protocol Composition

An existential can also creating by writing `any` before a protocol composition type (see <doc:Protocols#Protocol-Composition>). This creates a box which holds a structure, class or enum that conforms to all the protocols listed.

```
protocol Named {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this protocol is also defined in line 1629 of the "Protocols" chapter

var name: String { get }
}
protocol Aged {
var age: Int { get }
}
struct Person: Named, Aged {
var name: String
var age: Int
}
struct Dog: Named, Aged {
var name: String
var age: Int
var breed: String
}
var family: [any (Name & Aged)]
```

## Differences Between Opaque Types and Boxed Protocol Types

Returning an opaque type looks very similar
Expand Down
40 changes: 22 additions & 18 deletions TSPL.docc/LanguageGuide/Protocols.md
Original file line number Diff line number Diff line change
Expand Up @@ -755,10 +755,24 @@ a nonfailable initializer or an implicitly unwrapped failable initializer.
## Protocols as Types

Protocols don't actually implement any functionality themselves.
Regardless, you can use a protocol as a type in your code.
Regardless, you can use a protocol as a type in your code, for example as the type of a variable or function parameter.

The most common way to use a protocol as a type
is to use a protocol as a generic constraint.
```swift
func printFullName(_ fullyNamed: FullyNamed) {
print("The full name is \(fullyNamed.fullName)")
}

printFullName(ncc1701)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ncc1701 is defined on line 233

/// The full name is USS Enterprise
printFullName(john)
/// The full name is John

let ncc1701: FullyNamed = Starship(name: "Enterprise", prefix: "USS")
ncc1701.prefix // error! The type of the `ncc1701` variable is `FullyNamed`, not `Starship`.
```

Another common way to use a protocol as a type
is to use a protocol as a constraint on the type of a generic parameter (known as a generic constraint).
Code with generic constraints can work with
any type that conforms to the protocol,
and the specific type is chosen by the code that uses the API.
Expand All @@ -767,18 +781,8 @@ when you call a function that takes an argument
and that argument's type is generic,
the caller chooses the type.

Code with an opaque type
works with some type that conforms to the protocol.
The underlying type is known at compile time,
and the API implementation chooses that type,
but that type's identity is hidden from clients of the API.
Using an opaque type lets you prevent implementation details of an API
from leaking through the layer of abstraction ---
for example, by hiding the specific return type from a function,
and only guaranteeing that the value conforms to a given protocol.

Code with a boxed protocol type
works with any type, chosen at runtime, that conforms to the protocol.
Using a protocol as the type in a context where the conforming structure, class or enumeration is not statically known creates a boxed protocol type.
Such code works with any type, chosen at runtime, that conforms to the protocol.
To support this runtime flexibility,
Swift adds a level of indirection when necessary ---
known as a *box*,
Expand Down Expand Up @@ -1604,9 +1608,9 @@ that tries to adopt `SomeClassOnlyProtocol`.
## Protocol Composition

It can be useful to require a type to conform to multiple protocols at the same time.
You can combine multiple protocols into a single requirement
You can combine multiple protocols into a single *protocol composition type*
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The language reference calls this a "protocol composition type", but I think the compiler warnings call this a "protocol-constrained type" 🤔

with a *protocol composition*.
Protocol compositions behave as if you
Protocol composition behaves as if you
defined a temporary local protocol that has the combined requirements
of all protocols in the composition.
Protocol compositions don't define any new protocol types.
Expand All @@ -1619,7 +1623,7 @@ a protocol composition can also contain one class type,
which you can use to specify a required superclass.

Here's an example that combines two protocols called `Named` and `Aged`
into a single protocol composition requirement on a function parameter:
into a single protocol composition type, and using that as a requirement on a function parameter:

```swift
protocol Named {
Expand Down