Skip to content

Commit 3e6d741

Browse files
DougGregorxwu
andauthored
Add proposal "Opening existential arguments to optional parameters" (#1799)
* Add proposal "Opening existential arguments to optional parameters" * Update 0375-opening-existential-optional.md Co-authored-by: Xiaodi Wu <[email protected]>
1 parent c4e7455 commit 3e6d741

File tree

1 file changed

+71
-0
lines changed

1 file changed

+71
-0
lines changed
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Opening existential arguments to optional parameters
2+
3+
* Proposal: [SE-0375](0375-opening-existential-optional.md)
4+
* Authors: [Doug Gregor](https://github.com/DougGregor)
5+
* Review Manager: [Xiaodi Wu](https://github.com/xwu)
6+
* Status: **Active Review (October 11...25, 2022)**
7+
* Implementation: [apple/swift#61321](https://github.com/apple/swift/pull/61321)
8+
* Review: ([pitch](https://forums.swift.org/t/mini-pitch-for-se-0352-amendment-allow-opening-an-existential-argument-to-an-optional-parameter/60501))
9+
10+
## Introduction
11+
12+
[SE-0352 "Implicitly Opened Existentials"](https://github.com/apple/swift-evolution/blob/main/proposals/0352-implicit-open-existentials.md) has a limitation that prevents the opening of an existential argument when the corresponding parameter is optional. This proposal changes that behavior, so that such a call will succeed when a (non-optional) existential argument is passed to a parameter of optional type:
13+
14+
```swift
15+
func acceptOptional<T: P>(_ x: T?) { }
16+
func test(p: any P, pOpt: (any P)?) {
17+
acceptOptional(p) // SE-0352 does not open "p"; this proposal will open "p" and bind "T" to its underlying type
18+
acceptOptional(pOpt) // does not open "pOpt", because there is no "T" to bind to when "pOpt" is "nil"
19+
}
20+
```
21+
22+
The rationale for not opening the existential `p` in the first call was to ensure consistent behavior with the second call, in an effort to avoid confusion. SE-0352 says:
23+
24+
> The case of optionals is somewhat interesting. It's clear that the call `cannotOpen6(pOpt)` cannot work because `pOpt` could be `nil`, in which case there is no type to bind `T` to. We *could* choose to allow opening a non-optional existential argument when the parameter is optional, e.g.,
25+
>
26+
> ```
27+
> cannotOpen6(p1) // we *could* open here, binding T to the underlying type of p1, but choose not to
28+
> ```
29+
>
30+
> but this proposal doesn't allow this because it would be odd to allow this call but not the `cannotOpen6(pOpt)` call.
31+
32+
However, experience with implicitly-opened existentials has shown that opening an existential argument in the first case is important, because many functions accept optional parameters. It is possible to work around this limitation, but doing so requires a bit of boilerplate, using a generic function that takes a non-optional parameter as a trampoline to the one that takes an optional parameter:
33+
34+
```swift
35+
func acceptNonOptionalThunk<T: P>(_ x: T) {
36+
acceptOptional(x)
37+
}
38+
39+
func test(p: any P) {
40+
acceptNonOptionalThunk(p) // workaround for SE-0352 to get a call to acceptOptional with opened existential
41+
}
42+
```
43+
44+
## Proposed solution
45+
46+
Allow an argument of (non-optional) existential type to be opened to be passed to an optional parameter:
47+
48+
```swift
49+
func openOptional<T: P>(_ value: T?) { }
50+
51+
func testOpenToOptional(p: any P) {
52+
openOptional(p) // okay, opens 'p' and binds 'T' to its underlying type
53+
}
54+
```
55+
56+
## Source compatibility
57+
58+
Generally speaking, opening an existential argument in one more case will make code that would have been rejected by the compiler (e.g., with an error like "`P` does not conform to `P`") into code that is accepted, because the existential is opened. This can change the behavior of overload resulting, in the same manner as was [discussed in SE-0352](https://github.com/apple/swift-evolution/blob/main/proposals/0352-implicit-open-existentials.md#source-compatibility). Experience with SE-0352's integration into Swift 5.7 implies that the practical effect of these changes is quite small.
59+
60+
## Effect on ABI stability
61+
62+
This proposal changes the type system but has no ABI impact whatsoever.
63+
64+
## Effect on API resilience
65+
66+
This proposal changes the use of APIs, but not the APIs themselves, so it doesn't impact API resilience per se.
67+
68+
## Alternatives considered
69+
70+
Describe alternative approaches to addressing the same problem, and
71+
why you chose this approach instead.

0 commit comments

Comments
 (0)