<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body dir="auto"><div><br><br>Sent from my iPad</div><div><br>On Jun 5, 2016, at 5:02 AM, Patrick Pijnappel via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>&gt; wrote:<br><br></div><blockquote type="cite"><div><div dir="ltr">This has actually been proposed before, see SE-0073:&nbsp;<a href="https://github.com/apple/swift-evolution/blob/master/proposals/0073-noescape-once.md" target="_blank">https://github.com/apple/swift-evolution/blob/master/proposals/0073-noescape-once.md</a></div></div></blockquote><div><br></div>Actually that proposal was for noescape closures and this suggestion is for escaping closures. &nbsp;I don't think the compiler can verify this for noescape closures. &nbsp;If it is possible it would be far more complicated.<div><br><blockquote type="cite"><div><div dir="ltr"><div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Sun, Jun 5, 2016 at 11:37 AM, Charles Srstka via swift-evolution <span dir="ltr">&lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">MOTIVATION:<br>
<br>
As per the current situation, there is a pitfall when writing asynchronous APIs that does not occur when writing synchronous APIs. Consider the following synchronous API:<br>
<br>
func doSomething() -&gt; SomeEnum {<br>
&nbsp; &nbsp; &nbsp; &nbsp; if aCondition {<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if bCondition {<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return .Foo<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else {<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return .Bar<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br>
&nbsp; &nbsp; &nbsp; &nbsp; } else {<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if cCondition {<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return .Baz<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br>
&nbsp; &nbsp; &nbsp; &nbsp; }<br>
}<br>
<br>
The compiler will give an error here, since if both aCondition and cCondition are false, the function will not return anything.<br>
<br>
However, consider the equivalent async API:<br>
<br>
func doSomething(completionHandler: (SomeEnum) -&gt; ()) {<br>
&nbsp; &nbsp; &nbsp; &nbsp; dispatch_async(someQueue) {<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if aCondition {<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if bCondition {<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; completionHandler(.Foo)<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else {<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; completionHandler(.Bar)<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else {<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if cCondition {<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; completionHandler(.Baz)<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br>
&nbsp; &nbsp; &nbsp; &nbsp; }<br>
}<br>
<br>
Whoops, now the function can return without ever firing its completion handler, and the problem might not be discovered until runtime (and, depending on the complexity of the function, may be hard to find).<br>
<br>
PROPOSED SOLUTION:<br>
<br>
Add a @required attribute that can be applied to closure arguments. This attribute simply states that the given closure will always be eventually called, and the compiler can enforce this.<br>
<br>
DETAILED DESIGN:<br>
<br>
- The @required attribute states in our API contract that a given closure *must* be called at some point after the function is called.<br>
<br>
- Standard API calls like dispatch_async that contractually promise to execute a closure or block get @required added to their signatures.<br>
<br>
- When the compiler sees a @required closure in a function declaration, it checks to make sure that every execution path either calls the closure at some point, or sends a @required closure to another API that eventually ends up calling the closure.<br>
<br>
- If there’s a way for a @required closure not to be called, the compiler emits an error letting the developer know about the bug in his/her code.<br>
<br>
IMPACT ON EXISTING CODE:<br>
<br>
None. This is purely additive.<br>
<br>
ALTERNATIVES CONSIDERED:<br>
<br>
I got nothin’.<br>
<br>
Charles<br>
<br>
_______________________________________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
</blockquote></div><br></div></div>
</div></blockquote><blockquote type="cite"><div><span>_______________________________________________</span><br><span>swift-evolution mailing list</span><br><span><a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a></span><br><span><a href="https://lists.swift.org/mailman/listinfo/swift-evolution">https://lists.swift.org/mailman/listinfo/swift-evolution</a></span><br></div></blockquote></div></body></html>