<div dir="ltr">Storing into a member would be fine, as long as it must keep <span style="color:rgb(187,44,162);font-family:Menlo;font-size:11px">@once</span> as a type annotation and the compiler makes sure you maintain:<div><span style="font-family:Menlo;font-size:11px">    sum</span><font face="monospace, monospace">(callCount, storeCount, passCount) == 1</font><div><br></div><div>For example:</div><div>  <span style="color:rgb(187,44,162);font-family:Menlo;font-size:11px">class </span><span style="font-family:Menlo;font-size:11px">Example {</span><br><div><span style="color:rgb(187,44,162);font-family:Menlo;font-size:11px">    </span><span style="color:rgb(187,44,162);font-family:Menlo;font-size:11px">private </span><span style="color:rgb(187,44,162);font-family:Menlo;font-size:11px">var </span><span style="font-family:Menlo;font-size:11px">closure: (</span><span style="color:rgb(187,44,162);font-family:Menlo;font-size:11px">@once</span><span style="font-family:Menlo;font-size:11px"> (</span><span style="font-family:Menlo;font-size:11px">T) -&gt; </span><span style="font-family:Menlo;font-size:11px">Void)?</span></div><div><span style="font-family:Menlo;font-size:11px"><br></span></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span>    </span><span style="color:rgb(187,44,162)">func</span><span> callClosure(value: </span><span style="color:rgb(112,61,170)">T, </span>replace<span style="color:rgb(112,61,170)">: </span>(<span style="color:rgb(187,44,162)">@once</span> (T) -&gt; Void)? = <span style="color:rgb(187,44,162)">nil</span>) {</p><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span>      </span><span style="color:rgb(0,132,0)">// the compiler should error if it detects the closure:</span></p><p style="margin:0px;line-height:normal"><font color="#008400" style="font-family:Menlo;font-size:11px">      //  * escaping more than once, while still being </font><font color="#008400" face="Menlo"><span style="font-size:11px">stored,</span></font></p><p style="margin:0px;line-height:normal"><font color="#008400" face="Menlo"><span style="font-size:11px">      // </span></font><span style="color:rgb(0,132,0);font-family:Menlo;font-size:11px"> *</span><span style="color:rgb(0,132,0);font-family:Menlo;font-size:11px"> </span><span style="font-size:11px;color:rgb(0,132,0);font-family:Menlo">or being called while still being stored or escaping,</span></p><p style="margin:0px;line-height:normal"><font color="#008400" face="Menlo"><span style="font-size:11px">      // </span></font><span style="color:rgb(0,132,0);font-family:Menlo;font-size:11px"> *</span><span style="color:rgb(0,132,0);font-family:Menlo;font-size:11px"> </span><span style="font-size:11px;color:rgb(0,132,0);font-family:Menlo">or being overwritten without being called</span></p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span>      </span><span style="color:rgb(187,44,162)">if</span><span> </span><span style="color:rgb(187,44,162)">let</span><span> closure = </span><span style="color:rgb(187,44,162)">self</span><span>.closure {</span></p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span>        </span><span style="color:rgb(187,44,162)">self</span><span>.closure = </span>replace</p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span>        closure(value)</span></p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span>      }</span></p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span>    }</span></p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px"><span></span><br></p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span>    </span><span style="color:rgb(187,44,162)">deinit</span><span> {</span></p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span>      </span><span style="color:rgb(0,132,0)">// compiler warning: that closure is potentially un-called</span></p><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span style="color:rgb(0,132,0)">      // runtime fatalError if it&#39;s .Some(Closure) after deinit</span></p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span>    }</span></p><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span>  }</span></p></div><div><br></div><div>There could be a standard library type with those guarantees built in.</div><div><br></div></div></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Sun, Jun 5, 2016 at 10:12 PM, Matthew Johnson <span dir="ltr">&lt;<a href="mailto:matthew@anandabits.com" target="_blank">matthew@anandabits.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="auto"><div><br><br>Sent from my iPad</div><span class=""><div><br>On Jun 5, 2016, at 6:56 AM, Andrew Bennett &lt;<a href="mailto:cacoyi@gmail.com" target="_blank">cacoyi@gmail.com</a>&gt; wrote:<br><br></div><blockquote type="cite"><div><div dir="ltr">I like this.<div><br></div><div>One of the suggestions on @noescape(once) was that it just becomes @once and works with escaping closures too. It might be possible if compile time checks verified that the closure isn&#39;t copied, and that it is called before being deinit-ialized. Failing that I&#39;m happy with a runtime circumstance in the cases the compiler can&#39;t check.</div></div></div></blockquote><div><br></div></span>Yeah, maybe if it is only used asynchronously and never stored in a member or global it could be verified and that is a pretty common case.  That would certainly be easier than the general case.<div><br></div><div><div>I prefer @once over @required if the guarantee is single execution.  If the guarantee is *at least once* obviously @once is not the right attribute, but I&#39;m not convinced @required is either.  Maybe @invoked.</div><div><div class="h5"><div><br><blockquote type="cite"><div><div dir="ltr"><div><br></div><div>It would be great if @required took into the account the feedback from that proposal and considered the synchronous case too.</div><div><br></div><div>As an aside, you can get some of the guarantees you want like this:</div><div><br></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span style="color:rgb(187,44,162)">func</span><span> doSomething(completionHandler: (</span><span style="color:rgb(79,129,135)">SomeEnum</span><span>) -&gt; ()) {</span></p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(61,29,129)"><span style="color:rgb(0,0,0)">  </span><span>dispatch_async</span><span style="color:rgb(0,0,0)">(</span><span style="color:rgb(79,129,135)">someQueue</span><span style="color:rgb(0,0,0)">) {</span></p><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span>    </span><span style="color:rgb(187,44,162)">let</span><span> result: </span><span style="color:rgb(79,129,135)">SomeEnum</span></p><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span style="color:rgb(0,0,0)">    </span><span style="color:rgb(0,132,0)">// the compiler ensures &#39;result&#39; is set</span><span style="color:rgb(79,129,135)"><br></span></p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span>    </span><span style="color:rgb(187,44,162)">defer</span><span> { completionHandler(result) }</span></p><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span><br></span></p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(79,129,135)"><span style="color:rgb(0,0,0)">    </span><span style="color:rgb(187,44,162)">if</span><span style="color:rgb(0,0,0)"> </span><span>aCondition</span><span style="color:rgb(0,0,0)"> {</span></p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(79,129,135)"><span style="color:rgb(0,0,0)">      </span><span style="color:rgb(187,44,162)">if</span><span style="color:rgb(0,0,0)"> </span><span>bCondition</span><span style="color:rgb(0,0,0)"> {</span></p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span>        result = .</span><span style="color:rgb(49,89,93)">Foo</span></p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span>      } </span><span style="color:rgb(187,44,162)">else</span><span> {</span></p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span>        result = .</span><span style="color:rgb(49,89,93)">Bar</span></p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span>      }</span></p><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(0,132,0)"><span style="color:rgb(0,0,0)">      </span><span>// the compiler ensures you do this, because it is &#39;let&#39;</span></p><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">
</p><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span>      </span><span style="color:rgb(187,44,162)">return</span></p><div><span style="font-family:Menlo;font-size:11px">    </span><span style="font-family:Menlo;font-size:11px">}</span><br></div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span><br></span></p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(79,129,135)"><span style="color:rgb(0,0,0)">    </span><span style="color:rgb(187,44,162)">if</span><span style="color:rgb(0,0,0)"> </span><span>cCondition</span><span style="color:rgb(0,0,0)"> {</span></p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span>      result = .</span><span style="color:rgb(49,89,93)">Baz</span></p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span>    }</span></p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span>  }</span></p>
<p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span>}</span></p><div class="gmail_extra"><br><div class="gmail_quote">On Sun, Jun 5, 2016 at 9:42 PM, Matthew Johnson 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:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="auto"><div><br><br>Sent from my iPad</div><span><div><br>On Jun 5, 2016, at 5:02 AM, Patrick Pijnappel via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" target="_blank">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: <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></span>Actually that proposal was for noescape closures and this suggestion is for escaping closures.  I don&#39;t think the compiler can verify this for noescape closures.  If it is possible it would be far more complicated.<div><div><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:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style: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>
        if aCondition {<br>
                if bCondition {<br>
                        return .Foo<br>
                } else {<br>
                        return .Bar<br>
                }<br>
        } else {<br>
                if cCondition {<br>
                        return .Baz<br>
                }<br>
        }<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>
        dispatch_async(someQueue) {<br>
                if aCondition {<br>
                        if bCondition {<br>
                                completionHandler(.Foo)<br>
                        } else {<br>
                                completionHandler(.Bar)<br>
                        }<br>
                } else {<br>
                        if cCondition {<br>
                                completionHandler(.Baz)<br>
                        }<br>
                }<br>
        }<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" target="_blank">swift-evolution@swift.org</a></span><br><span><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a></span><br></div></blockquote></div></div></div></div><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>
<br></blockquote></div><br></div></div></div>
</div></blockquote></div></div></div></div></div></blockquote></div><br></div>