Skip to content

Commit a5a4f70

Browse files
committed
Merge pull request #221 from tjw/SR-842
First draft of proposal for <https://bugs.swift.org/browse/SR-842>.
2 parents dec4305 + c598de9 commit a5a4f70

File tree

1 file changed

+129
-0
lines changed

1 file changed

+129
-0
lines changed
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# Add Generic Result and Error Handling to autoreleasepool()
2+
3+
* Proposal: [SE-NNNN](https://github.com/apple/swift-evolution/blob/master/proposals/NNNN-autoreleasepool-signature.md)
4+
* Author(s): [Timothy J. Wood](https://github.com/tjw)
5+
* Status: **Awaiting review**
6+
* Review manager: TBD
7+
8+
## Introduction
9+
10+
The `autoreleasepool` function in the standard library does not currently
11+
support a return value or error handling, making it difficult and error-prone
12+
to pass results or errors from the body to the calling context.
13+
14+
Swift-evolution thread: A first call for discussion was
15+
[made here](https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160314/013054.html).
16+
Dmitri Gribenko pointed out that adding a generic return type would be useful
17+
(first in my premature pull request) and then also [here](https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160321/013059.html).
18+
Jordan Rose [pointed out](https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160321/013077.html)
19+
that care was needed to avoid inferring an incorrect return type for the body
20+
block, but after testing we confirmed that this is handled correctly by
21+
the compiler.
22+
23+
## Motivation
24+
25+
The current signature for `autoreleasepool` forces the creation of temporary
26+
variables to capture any results of the inner computation, as well as any error
27+
to eventually throw, in the case they are needed in the calling code. This extra
28+
boilerplate clutters up the intent, as well as introduces the risk of
29+
accidentally unwrapping a `nil` value.
30+
31+
For example:
32+
33+
```swift
34+
func doWork() throws -> Result {
35+
var result: Result? = nil
36+
var error: ErrorProtocol? = nil
37+
autoreleasepool {
38+
do {
39+
... actual computation which hopefully assigns to result but might not ...
40+
} catch let e {
41+
error = e
42+
}
43+
}
44+
guard let result = result else {
45+
throw error!
46+
}
47+
return result!
48+
}
49+
```
50+
51+
## Proposed solution
52+
53+
I'd like to propose altering the signature of the standard library
54+
`autoreleasepool` function to allow for a generic return type, as well as
55+
allowing a `throw` of an error:
56+
57+
```swift
58+
public func autoreleasepool<Result>(@noescape body: () throws -> Result) rethrows -> Result
59+
```
60+
61+
The case above becomes much more clear and less error-prone since the compiler
62+
can enforce that exactly one of the error and result are used:
63+
64+
```swift
65+
func doWork() throws -> Result {
66+
return try autoreleasepool {
67+
... actual computation which either returns or throws ...
68+
}
69+
}
70+
```
71+
72+
As an aside, since this proposes changing the signature already, I would like
73+
to further propose changing the argument label from `code` to `body`. This seems
74+
more in line with the parameter name used in the rest of the standard library,
75+
but isn't central to this proposal.
76+
77+
## Detailed design
78+
79+
The updated standard library function would read:
80+
81+
```swift
82+
public func autoreleasepool<Result>(@noescape body: () throws -> Result) rethrows -> Result {
83+
let pool = __pushAutoreleasePool()
84+
defer {
85+
__popAutoreleasePool(pool)
86+
}
87+
return try body()
88+
}
89+
```
90+
91+
## Impact on existing code
92+
93+
No impact expected.
94+
95+
## Alternatives considered
96+
97+
The [original request, SR-842](https://bugs.swift.org/browse/SR-842) only
98+
suggested adding `throws`, but Dmitri Gribenko pointed out that adding a generic
99+
return type would be better.
100+
101+
I also explored whether third-party code could wrap `autoreleasepool` themselves
102+
with something like:
103+
104+
```swift
105+
func autoreleasepool_generic<ResultType>(@noescape code: Void throws -> ResultType) rethrows -> ResultType {
106+
var result:ResultType?
107+
var error:ErrorProtocol?
108+
109+
autoreleasepool {
110+
do {
111+
result = try code()
112+
} catch let e {
113+
error = e
114+
}
115+
}
116+
117+
if let result = result {
118+
return result
119+
}
120+
121+
throw error! // Doesn't compile.
122+
}
123+
```
124+
125+
but this doesn't compile, since in a function with `rethrows`, only the call to
126+
the passed in function that is marked as `throws` is allowed to throw.
127+
Even if it was possible to create a `rethrows` wrapper from the non-throwing
128+
function, it is better to add the safety to the standard library in the
129+
first place.

0 commit comments

Comments
 (0)