[swift-evolution] An upcoming proposal for simplifying leak free, safe closures.

admin at wheerd.de admin at wheerd.de
Tue Jun 28 07:53:08 CDT 2016


Am 27.06.2016 20:55, schrieb Christopher Kornher:
>> On Jun 27, 2016, at 2:45 AM, Manuel Krebber via swift-evolution 
>> <swift-evolution at swift.org> wrote:
>> 
>> On 06/26/2016 09:10 PM, Christopher Kornher via swift-evolution wrote:
>>> The core proposal:
>>> ——————
>>> 
>>> Closures capturing object references should automatically capture all
>>> object references as weak.
>> In my code, most closures are used in a functional programming 
>> capacity,
>> e.g. with map(), reduce, etc. Hence, most closures are non-escaping 
>> and
>> local, where strong capture is the desired way. Otherwise I would have
>> to litter everything with optional unwrapping or add the explicit
>> capture definition which would both make the code less readable in my
>> opinion.
> 
> I thought about this some more and it makes sense to treat
> non-escaping closures are they are treated now. This might increase
> the burden on the compiler especially because these closures may not
> be declared inline. This would be far more straightforward than having
> to worry about changes to object existence within one or more
> invocations of a @nonescaping closure, especially in multi-threaded
> code.
> 
> I do not think that this would be a significant change for developers
> in practice. Any developer who would try to rely upon object
> references changing within the application of a @nonescaping closure
> would probably have read the manual very carefully :)
> 
> 

I am unsure whether treating closures differently depending on a 
@nonescaping attribute on a function is a good idea.
The problem is that, theoretically, the closure might be stored in a 
variable or used with different functions. Then how do you decide 
whether the default is strong or weak capture?

Example:

func f1(_ f : (Int) -> Int) {
...
}

func f2(_ f : @noescape  (Int) -> Int) {
...
}

let foo = Foo()
let f : (Int) -> Int = {
   return foo.x
}

f1(f)
f2(f)

In addition different default capture behaviour dependant on context 
could be confusing for developers I think.

>>> 1) Closures with object references could be simplified further by
>>> implicitly including ‘let’ guards for all object references:
>> This sounds good for closures without return value, but how would you
>> handle closures with non-optional non-void return values?
> 
> Good point.
> 
> 1) The simplest solution would be to have these closures require
> capture lists to some or all object references. Given the prevalence
> of the weak/strong dance, calling these out in some way probably
> should be done anyway.
> 
> 2) Another option would be to eliminate the implicit nil check guards,
> making all object references optional. The compiler would force these
> to be unwrapped, so users would be guided to do the right thing.
> 
> 3) Just always weakly capturing all object references would treat all
> closures uniformly.
> 

I think I favour 2) out of these, even though it still means the code 
will potentially be littered with ?. or let guards...

Kind regards, Manuel



More information about the swift-evolution mailing list