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:
- [swift-evolution] Guaranteed closure execution
- [swift-evolution] Guaranteed closure execution
Gwendal Roué
···
Le 5 mai 2016 à 18:16, Dmitri Gribenko <gribozavr@gmail.com> a écrit :
On Thu, May 5, 2016 at 3:27 AM, Gwendal Roué <gwendal.roue@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