Skip to content

Commit e38c9ea

Browse files
committed
First draft of proposal for <https://bugs.swift.org/browse/SR-842>.
1 parent 3d73a61 commit e38c9ea

File tree

1 file changed

+119
-0
lines changed

1 file changed

+119
-0
lines changed
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
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+
func doWork() throws -> Result {
34+
var result: Result? = nil
35+
var error: ErrorProtocol? = nil
36+
autoreleasepool {
37+
do {
38+
... actual computation which hopefully assigns to result but might not ...
39+
} catch let e {
40+
error = e
41+
}
42+
}
43+
guard let result = result else {
44+
throw error!
45+
}
46+
return result!
47+
}
48+
49+
## Proposed solution
50+
51+
I'd like to propose altering the signature of the standard library
52+
`autoreleasepool` function to allow for a generic return type, as well as
53+
allowing a `throw` of an error:
54+
55+
public func autoreleasepool<Result>(@noescape body: () throws -> Result) rethrows -> Result
56+
57+
The case above becomes much more clear and less error-prone since the compiler
58+
can enforce that exactly one of the error and result are used:
59+
60+
func doWork() throws -> Result {
61+
return try autoreleasepool {
62+
... actual computation which either returns or throws ...
63+
}
64+
}
65+
66+
As an aside, since this proposes changing the signature already, I would like
67+
to further propose changing the argument label from `code` to `body`. This seems
68+
more in line with the parameter name used in the rest of the standard library,
69+
but isn't central to this proposal.
70+
71+
## Detailed design
72+
73+
The updated standard library function would read:
74+
75+
public func autoreleasepool<Result>(@noescape body: () throws -> Result) rethrows -> Result {
76+
let pool = __pushAutoreleasePool()
77+
defer {
78+
__popAutoreleasePool(pool)
79+
}
80+
return try body()
81+
}
82+
83+
## Impact on existing code
84+
85+
No impact expected.
86+
87+
## Alternatives considered
88+
89+
The [original request, SR-842](https://bugs.swift.org/browse/SR-842) only
90+
suggested adding `throws`, but Dmitri Gribenko pointed out that adding a generic
91+
return type would be better.
92+
93+
I also explored whether third-party code could wrap `autoreleasepool` themselves
94+
with something like:
95+
96+
func autoreleasepool_generic<ResultType>(@noescape code: Void throws -> ResultType) rethrows -> ResultType {
97+
var result:ResultType?
98+
var error:ErrorProtocol?
99+
100+
autoreleasepool {
101+
do {
102+
result = try code()
103+
} catch let e {
104+
error = e
105+
}
106+
}
107+
108+
if let result = result {
109+
return result
110+
}
111+
112+
throw error! // Doesn't compile.
113+
}
114+
115+
but this doesn't compile, since in a function with `rethrows`, only the call to
116+
the passed in function that is marked as `throws` is allowed to throw.
117+
Even if it was possible to create a `rethrows` wrapper from the non-throwing
118+
function, it is better to add the safety to the standard library in the
119+
first place.

0 commit comments

Comments
 (0)