[swift-evolution] [Review] SE-0073: Marking closures as executing exactly once

Dmitri Gribenko gribozavr at gmail.com
Thu May 5 11:16:02 CDT 2016


On Thu, May 5, 2016 at 3:27 AM, Gwendal Roué <gwendal.roue at gmail.com> wrote:
>>> I quite expect being able to throw out of a @noescape(once) block. Maybe the sentence "it must not be executed on any path that throws" should be removed from the proposal, should it have the implications you describe.
>>>
>>> Here is below what I expect this proposal to allow. So you see one problematic case?
>>
>> Hi Gwendal,
>>
>> What about the following case?
>>
>> // Function which rethrows closure errors:
>> func f1(closure: @noescape(once) () throws -> ()) rethrows {
>>  try closure()
>> }
>>
>> let x: AnyObject
>> f1 {
>>  if someCondition() { x = MyClass() }
>>  if someOtherCondition() { throw MyError.Error() }
>>  x = MyOtherClass()
>> }
>>
>> How do you handle memory management for 'x' on the path that throws?
>> If the rule is that upon returning from f1 via a throw the variable
>> 'x' should not be initialized, then the closure passed to f1 has to
>> guarantee the deinitialization.  But f1 accepts an arbitrary closure.
>
> Hello Dmitri,
>
> To reason about @noescape(once) functions, the easiest way is to replace them with `do`:
>
>     let x: AnyObject
>     do {
>         if someCondition() { x = MyClass() }
>         if someOtherCondition() { throw MyError.error }
>         x = MyOtherClass()
>     }
>
> This code does not compile because x can't be initialized to MyOtherClass().
>
> But I don't think this is your point. Your point was "how can the compiler handle memory management ?".
>
> I can't answer this question, because I'm not competent enough. But if it can handle the do { … } case, can't it also handle the f { … } case?

The difference is that the do{} case is type checked and codegen'ed
together with the rest of the function.  The f{} case has two
functions that are type checked and codegen'ed more or less
separately (the function that contains the call to f, and the closure
itself).  Moreover, with do{} the placement of the code block is
fixed.  With f{}, you can save a closure in a variable and then call
f(myClosure).  How would that affect the rules?  How would you
implement the desired analysis?

Dmitri

-- 
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr at gmail.com>*/


More information about the swift-evolution mailing list