Immediately-called closures should be considered @noescape

Here’s a little annoyance I ran across just now:

            let sub: CKSubscription = {
                if let ID = self.ID {
                    return CKSubscription(recordType: typeName, predicate: predicate, subscriptionID: ID, options: allMutations)
                }
                else {
                    return CKSubscription(recordType: typeName, predicate: predicate, options: allMutations)
                }
            }()

This closure obviously never leaves the enclosing function, but Swift doesn’t treat it as if it had been passed to a @noescape function, so I have to say “self.ID” instead of “ID” in the condition. That’s a bit irritating, and I’d like to see it improved.

···

--
Brent Royal-Gordon
Architechies

Seems reasonable, especially because SILGen peepholes { }() so that it doesn't even allocate a closure to begin with.

-Joe

···

On Dec 15, 2015, at 3:16 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

Here’s a little annoyance I ran across just now:

           let sub: CKSubscription = {
               if let ID = self.ID {
                   return CKSubscription(recordType: typeName, predicate: predicate, subscriptionID: ID, options: allMutations)
               }
               else {
                   return CKSubscription(recordType: typeName, predicate: predicate, options: allMutations)
               }
           }()

This closure obviously never leaves the enclosing function, but Swift doesn’t treat it as if it had been passed to a @noescape function, so I have to say “self.ID” instead of “ID” in the condition. That’s a bit irritating, and I’d like to see it improved.

I’m pretty sure this is already the case, is it not? Perhaps this is only happening in a function body context, but not in a property initializer?

-Chris

···

On Dec 15, 2015, at 3:16 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

Here’s a little annoyance I ran across just now:

           let sub: CKSubscription = {
               if let ID = self.ID {
                   return CKSubscription(recordType: typeName, predicate: predicate, subscriptionID: ID, options: allMutations)
               }
               else {
                   return CKSubscription(recordType: typeName, predicate: predicate, options: allMutations)
               }
           }()

This closure obviously never leaves the enclosing function, but Swift doesn’t treat it as if it had been passed to a @noescape function, so I have to say “self.ID” instead of “ID” in the condition. That’s a bit irritating, and I’d like to see it improved.

Would the following be acceptable, or too dense?

let sub = ID.map { id in
  CKSubscription(recordType: typeName, predicate: predicate, subscriptionID: id, options: allMutations)
} ?? CKSubscription(recordType: typeName, predicate: predicate, options: allMutations)

Either way, I agree that immediately called closures should be implicitly @noescape.

···

On 15 Dec 2015, at 23:16, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

Here’s a little annoyance I ran across just now:

           let sub: CKSubscription = {
               if let ID = self.ID {
                   return CKSubscription(recordType: typeName, predicate: predicate, subscriptionID: ID, options: allMutations)
               }
               else {
                   return CKSubscription(recordType: typeName, predicate: predicate, options: allMutations)
               }
           }()

This closure obviously never leaves the enclosing function, but Swift doesn’t treat it as if it had been passed to a @noescape function, so I have to say “self.ID” instead of “ID” in the condition. That’s a bit irritating, and I’d like to see it improved.

Here’s a little annoyance I ran across just now:

          let sub: CKSubscription = {
              if let ID = self.ID {
                  return CKSubscription(recordType: typeName, predicate: predicate, subscriptionID: ID, options: allMutations)
              }
              else {
                  return CKSubscription(recordType: typeName, predicate: predicate, options: allMutations)
              }
          }()

This closure obviously never leaves the enclosing function, but Swift doesn’t treat it as if it had been passed to a @noescape function, so I have to say “self.ID” instead of “ID” in the condition. That’s a bit irritating, and I’d like to see it improved.

Would the following be acceptable, or too dense?

let sub = ID.map { id in
CKSubscription(recordType: typeName, predicate: predicate, subscriptionID: id, options: allMutations)
} ?? CKSubscription(recordType: typeName, predicate: predicate, options: allMutations)

It’s clever, but a little too clever even for my code.

(Really, the actual problem in this piece of code is that you can’t pass a nil subscriptionID to CKSubscription’s initializer even though there’s a parallel initializer which omits that parameter. Some people just want to watch the world burn, I guess.)

···

--
Brent Royal-Gordon
Architechies

+1 from me as well. Personally, I would consider this an enhancement to an existing feature and would therefore not need to have it go through formal review. I don't think I get to make this call, though.

Jordan

···

On Dec 15, 2015, at 15:20 , Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

On Dec 15, 2015, at 3:16 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

Here’s a little annoyance I ran across just now:

          let sub: CKSubscription = {
              if let ID = self.ID {
                  return CKSubscription(recordType: typeName, predicate: predicate, subscriptionID: ID, options: allMutations)
              }
              else {
                  return CKSubscription(recordType: typeName, predicate: predicate, options: allMutations)
              }
          }()

This closure obviously never leaves the enclosing function, but Swift doesn’t treat it as if it had been passed to a @noescape function, so I have to say “self.ID” instead of “ID” in the condition. That’s a bit irritating, and I’d like to see it improved.

Seems reasonable, especially because SILGen peepholes { }() so that it doesn't even allocate a closure to begin with.