For Some closures in Swift 4.1 we don't seem to need to mention how self is captured

Overview:

I have an example where in certain cases Swift 4.1 allows me to refer to an ivar in a closure without a capture list or without specifying self.ivar

Prior to Swift 4.1 it would throw a compilation error but in Swift 4.1 in some cases it does compile ok.

Code:

class Car {
    
    var price = 100
    
    func f1(context: NSManagedObjectContext) {
        
        context.performAndWait {
            
            price = 110 //Why is this not a syntactic error in Swift 4.1 ?
                        //So as a user how would I know which closures don't require an explicit capture
                        //prior to Swift 4.1, either had to capture self as weak or use strong reference of self
                        //Has anything changed in Swift 4.1 in this regards
                        //Now in Swift 4.1 it allows me to use price without explicit mention how self is captured
        }
    }
    
    func f2() {
        
        DispatchQueue.main.async {
            
            price = 120 //Syntactic error as expected (same as prior to Swift 4.1)
                        //Here need to mention self.price or capture it as a weak reference.
                        //However in context.performAndWait it wasn't required
    }
}

Questions:

  1. Why in some cases, how self is to be captured (strong / weak) need not be explicitly mentioned ?
  2. How to know for which closures an explicit mention of how self is captured is not required ?
  3. Was this something introduced in Swift 4.1, if so is there a proposal / article / documentation where I can read more about this ?

The async function uses an @escaping closure, while performAndWait doesn't. I assume non-escaping closures do not require explicit capture semantics (since they are executed directly in the scope of the function they were passed to).

P.S. This applies to Swift 4.0 as well.

4 Likes

That is absolutely correct. If I recall correctly, in Swift 4.0, there were some bugs with how escaping-ness was propagated into closure literals, and sometimes an explicit self. was required where it should not have been.

3 Likes

Thanks a lot @anthonylatsis and @Slava_Pestov

That's pretty neat, didn't realise that, non-escaping closures would have the same life time I suppose.

I guess I was capturing it explicitly in many places that I can clean up. Thanks again !