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

Gwendal Roué gwendal.roue at gmail.com
Thu May 5 11:34:51 CDT 2016


> Le 5 mai 2016 à 18:16, Dmitri Gribenko <gribozavr at gmail.com> a écrit :
> 
> 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

I just have two messages by Chris Lattner who did not seem to foresee any big trouble. Of course this does not mean there aren't any, even maybe some pretty difficult one. The second message addresses more precisely your memory handling concerns:

- https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160125/008231.html
- https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20160125/008598.html

Gwendal Roué



More information about the swift-evolution mailing list