@noescape loop hole


(Fabian Ehrentraud) #1

The implemented change for closures being @noescape by default is awesome, but an important case was missed. When the closure is stored into a local variable, there currently is no way to make that variable non-escaping.

class A {
  
  let n: Int = 1
  var cp: (() -> Int)?
  
  func f1() {
    // when directly constructing a new closure in the function call, the compiler knows it will be non-escaping, and no explicit `self` is needed in the closure...
    f2(c: { n })
    
    // ... but when storing the closure in an intermediate variable, it is not assumed as non-escaping, and explicit `self` is needed, and also we cannot prevent that it can be stored in some escaping way
    let c: () -> Int = {
      // the closure variable would need to know if it is escaping or not, as this has impact on whether the user needs to think about problems with strong capture semantics
      return self.n
    }
    f2(c: c)
    
    // this should actually not be allowed, unless the closure c is marked as @escaping
    cp = c
  }
  
  func f2(c: () -> Int) -> Int {
    return c()
  }
  
}

Is this rather a bug in the implementation of SE-0103, or a new feature request?

best,
Fabian


(Félix Cloutier) #2

You might know already, but you can write f2 { n } instead of f2(c: { n }).

I checked my code and found that this isn't a problem over here. Inertia is the only thing that guides my opinion here, I think that I could be swayed one way or the other rather easily.

Félix

···

Le 25 août 2016 à 23:58:28, Fabian Ehrentraud via swift-evolution <swift-evolution@swift.org> a écrit :

The implemented change for closures being @noescape by default is awesome, but an important case was missed. When the closure is stored into a local variable, there currently is no way to make that variable non-escaping.

class A {
  
  let n: Int = 1
  var cp: (() -> Int)?
  
  func f1() {
    // when directly constructing a new closure in the function call, the compiler knows it will be non-escaping, and no explicit `self` is needed in the closure...
    f2(c: { n })
    
    // ... but when storing the closure in an intermediate variable, it is not assumed as non-escaping, and explicit `self` is needed, and also we cannot prevent that it can be stored in some escaping way
    let c: () -> Int = {
      // the closure variable would need to know if it is escaping or not, as this has impact on whether the user needs to think about problems with strong capture semantics
      return self.n
    }
    f2(c: c)
    
    // this should actually not be allowed, unless the closure c is marked as @escaping
    cp = c
  }
  
  func f2(c: () -> Int) -> Int {
    return c()
  }
  
}

Is this rather a bug in the implementation of SE-0103, or a new feature request?

best,
Fabian
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Jordan Rose) #3

That’s not really a loophole, because nothing unsafe can happen because of it. It’s just a missing feature. Personally I think the added complexity from allowing non-parameter closures to be marked non-escaping makes it not worth the effort.

Jordan

···

On Aug 25, 2016, at 23:58, Fabian Ehrentraud via swift-evolution <swift-evolution@swift.org> wrote:

The implemented change for closures being @noescape by default is awesome, but an important case was missed. When the closure is stored into a local variable, there currently is no way to make that variable non-escaping.

class A {
  
  let n: Int = 1
  var cp: (() -> Int)?
  
  func f1() {
    // when directly constructing a new closure in the function call, the compiler knows it will be non-escaping, and no explicit `self` is needed in the closure...
    f2(c: { n })
    
    // ... but when storing the closure in an intermediate variable, it is not assumed as non-escaping, and explicit `self` is needed, and also we cannot prevent that it can be stored in some escaping way
    let c: () -> Int = {
      // the closure variable would need to know if it is escaping or not, as this has impact on whether the user needs to think about problems with strong capture semantics
      return self.n
    }
    f2(c: c)
    
    // this should actually not be allowed, unless the closure c is marked as @escaping
    cp = c
  }
  
  func f2(c: () -> Int) -> Int {
    return c()
  }
  
}

Is this rather a bug in the implementation of SE-0103, or a new feature request?

best,
Fabian
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution