Guaranteed closure execution

Hello,

I’d like to discuss the opportunity to let functions declare that a closure argument is guaranteed to have been executed when the function has returned.

For example:

  func f(@noescape(executed) closure: () -> ()) {
      closure()
  }

The expected advantage is that the compiler would know that a variable set inside the closure is guaranteed to be initialized, and that it can be used after the execution of the function, as below:

  let x: Int // Not initialized
  f { x = 1 }
  print(x) // Guaranteed to be initialized

Today developers have to write pessimistic code like below:

  var x: Int = 0 // `var` declaration, with some irrelevant value
  f { x = 1 }
  print(x)

As for a real world usage, I’d like to access a database in a safe (queued) way, and fetch values out of it:

  let items: [Item]
  let users: [User]
  dbQueue.inDatabase { db in
      items = Item.all().fetchAll(db)
      users = Item.all().fetchAll(db)
  }

Gwendal Roué

I've wanted something like this as well. I think it would be harder than it
seems, because "x = 1" might need to perform initialization, or assignment,
depending how it's used.

It could make sense to have something like
"@noescape(executed_exactly_once)" but this might be so limited it's not
worth it. And I'm not sure how it should interact with throws.

Jacob

···

On Thu, Jan 28, 2016 at 11:38 PM, Gwendal Roué <swift-evolution@swift.org> wrote:

Hello,

I’d like to discuss the opportunity to let functions declare that a
closure argument is guaranteed to have been executed when the function has
returned.

For example:

func f(@noescape(executed) closure: () -> ()) {
    closure()
}

The expected advantage is that the compiler would know that a variable set
inside the closure is guaranteed to be initialized, and that it can be used
after the execution of the function, as below:

let x: Int // Not initialized
f { x = 1 }
print(x) // Guaranteed to be initialized

Today developers have to write pessimistic code like below:

var x: Int = 0 // `var` declaration, with some irrelevant value
f { x = 1 }
print(x)

As for a real world usage, I’d like to access a database in a safe
(queued) way, and fetch values out of it:

let items: [Item]
let users: [User]
dbQueue.inDatabase { db in
    items = Item.all().fetchAll(db)
    users = Item.all().fetchAll(db)
}

Gwendal Roué

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

I've wanted something like this as well. I think it would be harder than it seems, because "x = 1" might need to perform initialization, or assignment, depending how it's used.

It could make sense to have something like "@noescape(executed_exactly_once)" but this might be so limited it's not worth it. And I'm not sure how it should interact with throws.

I think that something like this is implementable, and making it a modifier to @noescape is sensible.

The semantics we could support is that the function is guaranteed to call the closure exactly once on any path that could lead to a return or throw.

This approach allows you to pass the closure down the stack, and composes with error handling. It is obviously limited what you can do with the closure, but that is necessary to validate correctness.

-Chris

···

On Jan 29, 2016, at 12:23 AM, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org> wrote:

Jacob

On Thu, Jan 28, 2016 at 11:38 PM, Gwendal Roué <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Hello,

I’d like to discuss the opportunity to let functions declare that a closure argument is guaranteed to have been executed when the function has returned.

For example:

  func f(@noescape(executed) closure: () -> ()) {
      closure()
  }

The expected advantage is that the compiler would know that a variable set inside the closure is guaranteed to be initialized, and that it can be used after the execution of the function, as below:

  let x: Int // Not initialized
  f { x = 1 }
  print(x) // Guaranteed to be initialized

Today developers have to write pessimistic code like below:

  var x: Int = 0 // `var` declaration, with some irrelevant value
  f { x = 1 }
  print(x)

As for a real world usage, I’d like to access a database in a safe (queued) way, and fetch values out of it:

  let items: [Item]
  let users: [User]
  dbQueue.inDatabase { db in
      items = Item.all().fetchAll(db)
      users = Item.all().fetchAll(db)
  }

Gwendal Roué

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

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

Glad we’re a few longing for this feature :slight_smile:

You are right Jacob, a modifier `@noescape(once)` would be better, as it would help compiler distinguish between assignment and initialization of captured variables.

The utility of such a new feature is maybe tiny, but clear: it extends the opportunities to declare variables before initializing them. The Swift 1 to 2 transition has already extended those opportunities, so we’re just following an existing trend, here.

As for throwing functions, here is a few proposals:

# No errors

  func f(@noescape(once) once: () ()) {
    once()
  }
  let x: Int
  f { x = 1 }
  print(x) // OK
  
# Function declared as throws

  func f(@noescape(once) once: () throws -> ()) throws {
    try once()
  }
  let x: Int
  do {
    try f { x = try ... }
    print(x) // OK: function did not throw so x is initialized
  } catch {
    print(x) // BAD: y may not be initialized
  }

# Function declared as rethrows

  func f(@noescape(once) once: () throws -> ()) rethrows {
    try once()
  }
  
  let x: Int
  f { x = 1 }
  print(x) // OK: function did not throw so x is initialized

  let x: Int
  do {
    try f { x = try ... }
    print(x) // OK: function did not throw so x is initialized
  } catch {
    print(x) // BAD: y may not be initialized
  }

When a rethrowing function has several throwing closures, it does not change much. Generally, if the function throws, then the variable may not be initialized. If it does not throw, the variable is surely initialized.

Gwendal

···

Le 29 janv. 2016 à 09:23, Jacob Bandes-Storch <jtbandes@gmail.com> a écrit :

I've wanted something like this as well. I think it would be harder than it seems, because "x = 1" might need to perform initialization, or assignment, depending how it's used.

It could make sense to have something like "@noescape(executed_exactly_once)" but this might be so limited it's not worth it. And I'm not sure how it should interact with throws.

Jacob

On Thu, Jan 28, 2016 at 11:38 PM, Gwendal Roué <swift-evolution@swift.org> wrote:
Hello,

I’d like to discuss the opportunity to let functions declare that a closure argument is guaranteed to have been executed when the function has returned.

For example:

  func f(@noescape(executed) closure: () -> ()) {
      closure()
  }

The expected advantage is that the compiler would know that a variable set inside the closure is guaranteed to be initialized, and that it can be used after the execution of the function, as below:

  let x: Int // Not initialized
  f { x = 1 }
  print(x) // Guaranteed to be initialized

Today developers have to write pessimistic code like below:

  var x: Int = 0 // `var` declaration, with some irrelevant value
  f { x = 1 }
  print(x)

As for a real world usage, I’d like to access a database in a safe (queued) way, and fetch values out of it:

  let items: [Item]
  let users: [User]
  dbQueue.inDatabase { db in
      items = Item.all().fetchAll(db)
      users = Item.all().fetchAll(db)
  }

Gwendal Roué

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

You are right Jacob, a modifier `@noescape(once)` would be better, as it would help compiler distinguish between assignment and initialization of captured variables.

The utility of such a new feature is maybe tiny, but clear: it extends the opportunities to declare variables before initializing them. The Swift 1 to 2 transition has already extended those opportunities, so we’re just following an existing trend, here.

I actually think that `once` is orthogonal to `noescape`. There are a *lot* of closures that are not noescape, but are called exactly once, such as dispatch_async and most completion handlers.

···

--
Brent Royal-Gordon
Architechies

I don't have much to add but I also think that it would be nice to have.

Félix

···

Le 29 janv. 2016 à 12:38:01, Chris Lattner via swift-evolution <swift-evolution@swift.org> a écrit :

On Jan 29, 2016, at 12:23 AM, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I've wanted something like this as well. I think it would be harder than it seems, because "x = 1" might need to perform initialization, or assignment, depending how it's used.

It could make sense to have something like "@noescape(executed_exactly_once)" but this might be so limited it's not worth it. And I'm not sure how it should interact with throws.

I think that something like this is implementable, and making it a modifier to @noescape is sensible.

The semantics we could support is that the function is guaranteed to call the closure exactly once on any path that could lead to a return or throw.

This approach allows you to pass the closure down the stack, and composes with error handling. It is obviously limited what you can do with the closure, but that is necessary to validate correctness.

-Chris

Jacob

On Thu, Jan 28, 2016 at 11:38 PM, Gwendal Roué <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Hello,

I’d like to discuss the opportunity to let functions declare that a closure argument is guaranteed to have been executed when the function has returned.

For example:

  func f(@noescape(executed) closure: () -> ()) {
      closure()
  }

The expected advantage is that the compiler would know that a variable set inside the closure is guaranteed to be initialized, and that it can be used after the execution of the function, as below:

  let x: Int // Not initialized
  f { x = 1 }
  print(x) // Guaranteed to be initialized

Today developers have to write pessimistic code like below:

  var x: Int = 0 // `var` declaration, with some irrelevant value
  f { x = 1 }
  print(x)

As for a real world usage, I’d like to access a database in a safe (queued) way, and fetch values out of it:

  let items: [Item]
  let users: [User]
  dbQueue.inDatabase { db in
      items = Item.all().fetchAll(db)
      users = Item.all().fetchAll(db)
  }

Gwendal Roué

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

I'm very supportive of this type of proposal.

I do agree with Brent though that @noescape and 'once' is somewhat orthogonal.

There are a lot of places where you want to be clear that the block will be called but no more than once. For example, the NSURLSession callback blocks you would expect never to be called multiple times. Completion handlers are almost always used only once. I don't think this case, which is extremely common, can be overlooked.

On the other hand, I suspect the majority of places you use closures with @noescape, it seems more likely you'd want it used multiple times, like a search, filter, find etc of multiple items in a collection or group, otherwise you'd generally just put the closured activity before or after. The only areas where I would expect to see such closures of @noescape and 'once' would be dispatch_sync, or somewhere where you want to invoke custom code in the middle of a complex operation of a method.

It seems to me that separating them, but allowing them to be used together, makes more sense.

Rod

···

On 30 Jan 2016, at 5:05 AM, Félix Cloutier via swift-evolution <swift-evolution@swift.org> wrote:

I don't have much to add but I also think that it would be nice to have.

Félix

Le 29 janv. 2016 à 12:38:01, Chris Lattner via swift-evolution <swift-evolution@swift.org> a écrit :

On Jan 29, 2016, at 12:23 AM, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org> wrote:

I've wanted something like this as well. I think it would be harder than it seems, because "x = 1" might need to perform initialization, or assignment, depending how it's used.

It could make sense to have something like "@noescape(executed_exactly_once)" but this might be so limited it's not worth it. And I'm not sure how it should interact with throws.

I think that something like this is implementable, and making it a modifier to @noescape is sensible.

The semantics we could support is that the function is guaranteed to call the closure exactly once on any path that could lead to a return or throw.

This approach allows you to pass the closure down the stack, and composes with error handling. It is obviously limited what you can do with the closure, but that is necessary to validate correctness.

-Chris

Jacob

On Thu, Jan 28, 2016 at 11:38 PM, Gwendal Roué <swift-evolution@swift.org> wrote:
Hello,

I’d like to discuss the opportunity to let functions declare that a closure argument is guaranteed to have been executed when the function has returned.

For example:

  func f(@noescape(executed) closure: () -> ()) {
      closure()
  }

The expected advantage is that the compiler would know that a variable set inside the closure is guaranteed to be initialized, and that it can be used after the execution of the function, as below:

  let x: Int // Not initialized
  f { x = 1 }
  print(x) // Guaranteed to be initialized

Today developers have to write pessimistic code like below:

  var x: Int = 0 // `var` declaration, with some irrelevant value
  f { x = 1 }
  print(x)

As for a real world usage, I’d like to access a database in a safe (queued) way, and fetch values out of it:

  let items: [Item]
  let users: [User]
  dbQueue.inDatabase { db in
      items = Item.all().fetchAll(db)
      users = Item.all().fetchAll(db)
  }

Gwendal Roué

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

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

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

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

The "noescape + exactly once" guarantee is useful to the compiler because
it allows the closure to *initialize* variables that it captures. The way
to think about this is that the closure body is effectively inlined.

"noescape, but not exactly once" is still useful because you can omit
references to self, and know that variable modifications in the closure
will be visible after the function call. But you can't perform
initialization (because the closure might be called more than once), nor
can you be sure variables are initialized after the function call (because
the closure might not be called at all).

"exactly once, but escaping" is an important API contract that should be
documented, but if the closure can escape the call, then you still can't
perform initialization in the closure, because the order it happens in
w.r.t. the function call isn't guaranteed. I might be missing something,
but I don't see any reason for this feature to exist, because...well, it
isn't really a feature if it can't do anything.

Jacob

···

On Sat, Jan 30, 2016 at 12:07 PM, Matthew Johnson via swift-evolution < swift-evolution@swift.org> wrote:

On Jan 30, 2016, at 1:56 PM, Félix Cloutier via swift-evolution < > swift-evolution@swift.org> wrote:

I agree that many closures are expected to be executed only once, but it
seems to me that it's only useful to the compiler if it's also marked
@noescape. A completion handler marked "once" without "noescape" doesn't
allow the compiler to determine that a variable will have been initialized
after the call that takes the closure.

So in these other cases, it only serves as documentation. I'm not very
enthusiastic about attributes that only serve as documentation because
there is an infinity of attributes that can be added to the language for
documentation purposes.

It also serves as a guarantee that the closure is executed exactly once.
Even if the compiler can’t use it for optimization the guarantee could be
useful.

There are other places than `dispatch_sync` where you may want a
`@noescape(once)` attribute. Any function that executes a closure while
providing some sort of guarantee/RAII-like handle can benefit from it. Most
of the functions starting with `with` in the standard library could benefit
from it: withExtendedLifetime, withUnsafePointer and friends, withVaList.
String's `withCString` and `withMutableCharacters` could benefit from it
too. Someone who writes a `withLock(lock) { closure }` function would be
happy to have it too.

Félix

Le 30 janv. 2016 à 07:11:23, Rod Brown <rodney.brown6@icloud.com> a écrit
:

I'm very supportive of this type of proposal.

I do agree with Brent though that @noescape and 'once' is somewhat
orthogonal.

There are a lot of places where you want to be clear that the block will
be called but no more than once. For example, the NSURLSession callback
blocks you would expect never to be called multiple times. Completion
handlers are almost always used only once. I don't think this case, which
is extremely common, can be overlooked.

On the other hand, I suspect the majority of places you use closures with
@noescape, it seems more likely you'd *want *it used multiple times, like
a search, filter, find etc of multiple items in a collection or group,
otherwise you'd generally just put the closured activity before or after.
The only areas where I would expect to see such closures of @noescape and
'once' would be dispatch_sync, or somewhere where you want to invoke custom
code in the middle of a complex operation of a method.

It seems to me that separating them, but allowing them to be used
together, makes more sense.

Rod

On 30 Jan 2016, at 5:05 AM, Félix Cloutier via swift-evolution < > swift-evolution@swift.org> wrote:

I don't have much to add but I also think that it would be nice to have.

Félix

Le 29 janv. 2016 à 12:38:01, Chris Lattner via swift-evolution < > swift-evolution@swift.org> a écrit :

On Jan 29, 2016, at 12:23 AM, Jacob Bandes-Storch via swift-evolution < > swift-evolution@swift.org> wrote:

I've wanted something like this as well. I think it would be harder than
it seems, because "x = 1" might need to perform initialization, or
assignment, depending how it's used.

It could make sense to have something like
"@noescape(executed_exactly_once)" but this might be so limited it's not
worth it. And I'm not sure how it should interact with throws.

I think that something like this is implementable, and making it a
modifier to @noescape is sensible.

The semantics we could support is that the function is guaranteed to call
the closure exactly once on any path that could lead to a return or throw.

This approach allows you to pass the closure down the stack, and composes
with error handling. It is obviously limited what you can do with the
closure, but that is necessary to validate correctness.

-Chris

Jacob

On Thu, Jan 28, 2016 at 11:38 PM, Gwendal Roué <swift-evolution@swift.org> > wrote:

Hello,

I’d like to discuss the opportunity to let functions declare that a
closure argument is guaranteed to have been executed when the function has
returned.

For example:

func f(@noescape(executed) closure: () -> ()) {
    closure()
}

The expected advantage is that the compiler would know that a variable
set inside the closure is guaranteed to be initialized, and that it can be
used after the execution of the function, as below:

let x: Int // Not initialized
f { x = 1 }
print(x) // Guaranteed to be initialized

Today developers have to write pessimistic code like below:

var x: Int = 0 // `var` declaration, with some irrelevant value
f { x = 1 }
print(x)

As for a real world usage, I’d like to access a database in a safe
(queued) way, and fetch values out of it:

let items: [Item]
let users: [User]
dbQueue.inDatabase { db in
    items = Item.all().fetchAll(db)
    users = Item.all().fetchAll(db)
}

Gwendal Roué

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

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

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

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

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

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

Can the compiler even enforce it? If the closure escapes, it necessarily means that you assigned it elsewhere. How do you enforce that you never call this reference more than once?

It isn’t. I agree with what I think you’re saying: noescape and “once” really are not orthogonal.

The combination of noescape+once is something the compiler can enforce, and because of that, it can provide improved initialization flexibility (and help make things like autoreleasepool feel more statement like).

The combination of escaping+once is not something the compiler can enforce, and becomes of that, it is little more than documentation. I’m a huge fan of documentation, but building it into the language like this would mislead people into thinking it IS enforced by the compiler. Also, this is not how we would build a documentation feature.

-Chris

···

On Jan 30, 2016, at 12:54 PM, Félix Cloutier via swift-evolution <swift-evolution@swift.org> wrote:

If the compiler can't take advantage of it and can't enforce it either, I would rather not have it at all.

I would also think that for a lot of APIs with an escaping closure, it could be more useful to say that it will be called "at most once" than "exactly once". Additionally, if completion blocks are the main client of the feature, I would avoid giving it too much effort before we figure out the favored concurrency model.

@noescape(once) really looks like a special case to me, because it's enforceable, useful to the compiler and useful to the user.

Félix

Le 30 janv. 2016 à 15:07:11, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> a écrit :

On Jan 30, 2016, at 1:56 PM, Félix Cloutier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I agree that many closures are expected to be executed only once, but it seems to me that it's only useful to the compiler if it's also marked @noescape. A completion handler marked "once" without "noescape" doesn't allow the compiler to determine that a variable will have been initialized after the call that takes the closure.

So in these other cases, it only serves as documentation. I'm not very enthusiastic about attributes that only serve as documentation because there is an infinity of attributes that can be added to the language for documentation purposes.

It also serves as a guarantee that the closure is executed exactly once. Even if the compiler can’t use it for optimization the guarantee could be useful.

There are other places than `dispatch_sync` where you may want a `@noescape(once)` attribute. Any function that executes a closure while providing some sort of guarantee/RAII-like handle can benefit from it. Most of the functions starting with `with` in the standard library could benefit from it: withExtendedLifetime, withUnsafePointer and friends, withVaList. String's `withCString` and `withMutableCharacters` could benefit from it too. Someone who writes a `withLock(lock) { closure }` function would be happy to have it too.

Félix

Le 30 janv. 2016 à 07:11:23, Rod Brown <rodney.brown6@icloud.com <mailto:rodney.brown6@icloud.com>> a écrit :

I'm very supportive of this type of proposal.

I do agree with Brent though that @noescape and 'once' is somewhat orthogonal.

There are a lot of places where you want to be clear that the block will be called but no more than once. For example, the NSURLSession callback blocks you would expect never to be called multiple times. Completion handlers are almost always used only once. I don't think this case, which is extremely common, can be overlooked.

On the other hand, I suspect the majority of places you use closures with @noescape, it seems more likely you'd want it used multiple times, like a search, filter, find etc of multiple items in a collection or group, otherwise you'd generally just put the closured activity before or after. The only areas where I would expect to see such closures of @noescape and 'once' would be dispatch_sync, or somewhere where you want to invoke custom code in the middle of a complex operation of a method.

It seems to me that separating them, but allowing them to be used together, makes more sense.

Rod

On 30 Jan 2016, at 5:05 AM, Félix Cloutier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I don't have much to add but I also think that it would be nice to have.

Félix

Le 29 janv. 2016 à 12:38:01, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

On Jan 29, 2016, at 12:23 AM, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I've wanted something like this as well. I think it would be harder than it seems, because "x = 1" might need to perform initialization, or assignment, depending how it's used.

It could make sense to have something like "@noescape(executed_exactly_once)" but this might be so limited it's not worth it. And I'm not sure how it should interact with throws.

I think that something like this is implementable, and making it a modifier to @noescape is sensible.

The semantics we could support is that the function is guaranteed to call the closure exactly once on any path that could lead to a return or throw.

This approach allows you to pass the closure down the stack, and composes with error handling. It is obviously limited what you can do with the closure, but that is necessary to validate correctness.

-Chris

Jacob

On Thu, Jan 28, 2016 at 11:38 PM, Gwendal Roué <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Hello,

I’d like to discuss the opportunity to let functions declare that a closure argument is guaranteed to have been executed when the function has returned.

For example:

  func f(@noescape(executed) closure: () -> ()) {
      closure()
  }

The expected advantage is that the compiler would know that a variable set inside the closure is guaranteed to be initialized, and that it can be used after the execution of the function, as below:

  let x: Int // Not initialized
  f { x = 1 }
  print(x) // Guaranteed to be initialized

Today developers have to write pessimistic code like below:

  var x: Int = 0 // `var` declaration, with some irrelevant value
  f { x = 1 }
  print(x)

As for a real world usage, I’d like to access a database in a safe (queued) way, and fetch values out of it:

  let items: [Item]
  let users: [User]
  dbQueue.inDatabase { db in
      items = Item.all().fetchAll(db)
      users = Item.all().fetchAll(db)
  }

Gwendal Roué

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

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

+1, exactly right.

-Chris

···

On Jan 30, 2016, at 12:19 PM, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org> wrote:

The "noescape + exactly once" guarantee is useful to the compiler because it allows the closure to *initialize* variables that it captures. The way to think about this is that the closure body is effectively inlined.

"noescape, but not exactly once" is still useful because you can omit references to self, and know that variable modifications in the closure will be visible after the function call. But you can't perform initialization (because the closure might be called more than once), nor can you be sure variables are initialized after the function call (because the closure might not be called at all).

"exactly once, but escaping" is an important API contract that should be documented, but if the closure can escape the call, then you still can't perform initialization in the closure, because the order it happens in w.r.t. the function call isn't guaranteed. I might be missing something, but I don't see any reason for this feature to exist, because...well, it isn't really a feature if it can't do anything.

I agree that many closures are expected to be executed only once, but it seems to me that it's only useful to the compiler if it's also marked @noescape. A completion handler marked "once" without "noescape" doesn't allow the compiler to determine that a variable will have been initialized after the call that takes the closure.

So in these other cases, it only serves as documentation. I'm not very enthusiastic about attributes that only serve as documentation because there is an infinity of attributes that can be added to the language for documentation purposes.

It also serves as a guarantee that the closure is executed exactly once. Even if the compiler can’t use it for optimization the guarantee could be useful.

···

On Jan 30, 2016, at 1:56 PM, Félix Cloutier via swift-evolution <swift-evolution@swift.org> wrote:

There are other places than `dispatch_sync` where you may want a `@noescape(once)` attribute. Any function that executes a closure while providing some sort of guarantee/RAII-like handle can benefit from it. Most of the functions starting with `with` in the standard library could benefit from it: withExtendedLifetime, withUnsafePointer and friends, withVaList. String's `withCString` and `withMutableCharacters` could benefit from it too. Someone who writes a `withLock(lock) { closure }` function would be happy to have it too.

Félix

Le 30 janv. 2016 à 07:11:23, Rod Brown <rodney.brown6@icloud.com <mailto:rodney.brown6@icloud.com>> a écrit :

I'm very supportive of this type of proposal.

I do agree with Brent though that @noescape and 'once' is somewhat orthogonal.

There are a lot of places where you want to be clear that the block will be called but no more than once. For example, the NSURLSession callback blocks you would expect never to be called multiple times. Completion handlers are almost always used only once. I don't think this case, which is extremely common, can be overlooked.

On the other hand, I suspect the majority of places you use closures with @noescape, it seems more likely you'd want it used multiple times, like a search, filter, find etc of multiple items in a collection or group, otherwise you'd generally just put the closured activity before or after. The only areas where I would expect to see such closures of @noescape and 'once' would be dispatch_sync, or somewhere where you want to invoke custom code in the middle of a complex operation of a method.

It seems to me that separating them, but allowing them to be used together, makes more sense.

Rod

On 30 Jan 2016, at 5:05 AM, Félix Cloutier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I don't have much to add but I also think that it would be nice to have.

Félix

Le 29 janv. 2016 à 12:38:01, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

On Jan 29, 2016, at 12:23 AM, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I've wanted something like this as well. I think it would be harder than it seems, because "x = 1" might need to perform initialization, or assignment, depending how it's used.

It could make sense to have something like "@noescape(executed_exactly_once)" but this might be so limited it's not worth it. And I'm not sure how it should interact with throws.

I think that something like this is implementable, and making it a modifier to @noescape is sensible.

The semantics we could support is that the function is guaranteed to call the closure exactly once on any path that could lead to a return or throw.

This approach allows you to pass the closure down the stack, and composes with error handling. It is obviously limited what you can do with the closure, but that is necessary to validate correctness.

-Chris

Jacob

On Thu, Jan 28, 2016 at 11:38 PM, Gwendal Roué <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Hello,

I’d like to discuss the opportunity to let functions declare that a closure argument is guaranteed to have been executed when the function has returned.

For example:

  func f(@noescape(executed) closure: () -> ()) {
      closure()
  }

The expected advantage is that the compiler would know that a variable set inside the closure is guaranteed to be initialized, and that it can be used after the execution of the function, as below:

  let x: Int // Not initialized
  f { x = 1 }
  print(x) // Guaranteed to be initialized

Today developers have to write pessimistic code like below:

  var x: Int = 0 // `var` declaration, with some irrelevant value
  f { x = 1 }
  print(x)

As for a real world usage, I’d like to access a database in a safe (queued) way, and fetch values out of it:

  let items: [Item]
  let users: [User]
  dbQueue.inDatabase { db in
      items = Item.all().fetchAll(db)
      users = Item.all().fetchAll(db)
  }

Gwendal Roué

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

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

I agree that many closures are expected to be executed only once, but it seems to me that it's only useful to the compiler if it's also marked @noescape. A completion handler marked "once" without "noescape" doesn't allow the compiler to determine that a variable will have been initialized after the call that takes the closure.

So in these other cases, it only serves as documentation. I'm not very enthusiastic about attributes that only serve as documentation because there is an infinity of attributes that can be added to the language for documentation purposes.

There are other places than `dispatch_sync` where you may want a `@noescape(once)` attribute. Any function that executes a closure while providing some sort of guarantee/RAII-like handle can benefit from it. Most of the functions starting with `with` in the standard library could benefit from it: withExtendedLifetime, withUnsafePointer and friends, withVaList. String's `withCString` and `withMutableCharacters` could benefit from it too. Someone who writes a `withLock(lock) { closure }` function would be happy to have it too.

Félix

···

Le 30 janv. 2016 à 07:11:23, Rod Brown <rodney.brown6@icloud.com> a écrit :

I'm very supportive of this type of proposal.

I do agree with Brent though that @noescape and 'once' is somewhat orthogonal.

There are a lot of places where you want to be clear that the block will be called but no more than once. For example, the NSURLSession callback blocks you would expect never to be called multiple times. Completion handlers are almost always used only once. I don't think this case, which is extremely common, can be overlooked.

On the other hand, I suspect the majority of places you use closures with @noescape, it seems more likely you'd want it used multiple times, like a search, filter, find etc of multiple items in a collection or group, otherwise you'd generally just put the closured activity before or after. The only areas where I would expect to see such closures of @noescape and 'once' would be dispatch_sync, or somewhere where you want to invoke custom code in the middle of a complex operation of a method.

It seems to me that separating them, but allowing them to be used together, makes more sense.

Rod

On 30 Jan 2016, at 5:05 AM, Félix Cloutier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I don't have much to add but I also think that it would be nice to have.

Félix

Le 29 janv. 2016 à 12:38:01, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

On Jan 29, 2016, at 12:23 AM, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I've wanted something like this as well. I think it would be harder than it seems, because "x = 1" might need to perform initialization, or assignment, depending how it's used.

It could make sense to have something like "@noescape(executed_exactly_once)" but this might be so limited it's not worth it. And I'm not sure how it should interact with throws.

I think that something like this is implementable, and making it a modifier to @noescape is sensible.

The semantics we could support is that the function is guaranteed to call the closure exactly once on any path that could lead to a return or throw.

This approach allows you to pass the closure down the stack, and composes with error handling. It is obviously limited what you can do with the closure, but that is necessary to validate correctness.

-Chris

Jacob

On Thu, Jan 28, 2016 at 11:38 PM, Gwendal Roué <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Hello,

I’d like to discuss the opportunity to let functions declare that a closure argument is guaranteed to have been executed when the function has returned.

For example:

  func f(@noescape(executed) closure: () -> ()) {
      closure()
  }

The expected advantage is that the compiler would know that a variable set inside the closure is guaranteed to be initialized, and that it can be used after the execution of the function, as below:

  let x: Int // Not initialized
  f { x = 1 }
  print(x) // Guaranteed to be initialized

Today developers have to write pessimistic code like below:

  var x: Int = 0 // `var` declaration, with some irrelevant value
  f { x = 1 }
  print(x)

As for a real world usage, I’d like to access a database in a safe (queued) way, and fetch values out of it:

  let items: [Item]
  let users: [User]
  dbQueue.inDatabase { db in
      items = Item.all().fetchAll(db)
      users = Item.all().fetchAll(db)
  }

Gwendal Roué

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

Can the compiler even enforce it? If the closure escapes, it necessarily means that you assigned it elsewhere. How do you enforce that you never call this reference more than once?

Good point. It would probably be difficult if not impossible to enforce.

If the compiler can't take advantage of it and can't enforce it either, I would rather not have it at all.

Agree, if there is no guarantee it is better to live it out.

···

On Jan 30, 2016, at 2:54 PM, Félix Cloutier <felixcca@yahoo.ca> wrote:

I would also think that for a lot of APIs with an escaping closure, it could be more useful to say that it will be called "at most once" than "exactly once". Additionally, if completion blocks are the main client of the feature, I would avoid giving it too much effort before we figure out the favored concurrency model.

@noescape(once) really looks like a special case to me, because it's enforceable, useful to the compiler and useful to the user.

Félix

Le 30 janv. 2016 à 15:07:11, Matthew Johnson <matthew@anandabits.com <mailto:matthew@anandabits.com>> a écrit :

On Jan 30, 2016, at 1:56 PM, Félix Cloutier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I agree that many closures are expected to be executed only once, but it seems to me that it's only useful to the compiler if it's also marked @noescape. A completion handler marked "once" without "noescape" doesn't allow the compiler to determine that a variable will have been initialized after the call that takes the closure.

So in these other cases, it only serves as documentation. I'm not very enthusiastic about attributes that only serve as documentation because there is an infinity of attributes that can be added to the language for documentation purposes.

It also serves as a guarantee that the closure is executed exactly once. Even if the compiler can’t use it for optimization the guarantee could be useful.

There are other places than `dispatch_sync` where you may want a `@noescape(once)` attribute. Any function that executes a closure while providing some sort of guarantee/RAII-like handle can benefit from it. Most of the functions starting with `with` in the standard library could benefit from it: withExtendedLifetime, withUnsafePointer and friends, withVaList. String's `withCString` and `withMutableCharacters` could benefit from it too. Someone who writes a `withLock(lock) { closure }` function would be happy to have it too.

Félix

Le 30 janv. 2016 à 07:11:23, Rod Brown <rodney.brown6@icloud.com <mailto:rodney.brown6@icloud.com>> a écrit :

I'm very supportive of this type of proposal.

I do agree with Brent though that @noescape and 'once' is somewhat orthogonal.

There are a lot of places where you want to be clear that the block will be called but no more than once. For example, the NSURLSession callback blocks you would expect never to be called multiple times. Completion handlers are almost always used only once. I don't think this case, which is extremely common, can be overlooked.

On the other hand, I suspect the majority of places you use closures with @noescape, it seems more likely you'd want it used multiple times, like a search, filter, find etc of multiple items in a collection or group, otherwise you'd generally just put the closured activity before or after. The only areas where I would expect to see such closures of @noescape and 'once' would be dispatch_sync, or somewhere where you want to invoke custom code in the middle of a complex operation of a method.

It seems to me that separating them, but allowing them to be used together, makes more sense.

Rod

On 30 Jan 2016, at 5:05 AM, Félix Cloutier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I don't have much to add but I also think that it would be nice to have.

Félix

Le 29 janv. 2016 à 12:38:01, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

On Jan 29, 2016, at 12:23 AM, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I've wanted something like this as well. I think it would be harder than it seems, because "x = 1" might need to perform initialization, or assignment, depending how it's used.

It could make sense to have something like "@noescape(executed_exactly_once)" but this might be so limited it's not worth it. And I'm not sure how it should interact with throws.

I think that something like this is implementable, and making it a modifier to @noescape is sensible.

The semantics we could support is that the function is guaranteed to call the closure exactly once on any path that could lead to a return or throw.

This approach allows you to pass the closure down the stack, and composes with error handling. It is obviously limited what you can do with the closure, but that is necessary to validate correctness.

-Chris

Jacob

On Thu, Jan 28, 2016 at 11:38 PM, Gwendal Roué <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Hello,

I’d like to discuss the opportunity to let functions declare that a closure argument is guaranteed to have been executed when the function has returned.

For example:

  func f(@noescape(executed) closure: () -> ()) {
      closure()
  }

The expected advantage is that the compiler would know that a variable set inside the closure is guaranteed to be initialized, and that it can be used after the execution of the function, as below:

  let x: Int // Not initialized
  f { x = 1 }
  print(x) // Guaranteed to be initialized

Today developers have to write pessimistic code like below:

  var x: Int = 0 // `var` declaration, with some irrelevant value
  f { x = 1 }
  print(x)

As for a real world usage, I’d like to access a database in a safe (queued) way, and fetch values out of it:

  let items: [Item]
  let users: [User]
  dbQueue.inDatabase { db in
      items = Item.all().fetchAll(db)
      users = Item.all().fetchAll(db)
  }

Gwendal Roué

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

Can the compiler even enforce it? If the closure escapes, it necessarily means that you assigned it elsewhere. How do you enforce that you never call this reference more than once?

If the compiler can't take advantage of it and can't enforce it either, I would rather not have it at all.

I would also think that for a lot of APIs with an escaping closure, it could be more useful to say that it will be called "at most once" than "exactly once". Additionally, if completion blocks are the main client of the feature, I would avoid giving it too much effort before we figure out the favored concurrency model.

@noescape(once) really looks like a special case to me, because it's enforceable, useful to the compiler and useful to the user.

Félix

···

Le 30 janv. 2016 à 15:07:11, Matthew Johnson <matthew@anandabits.com> a écrit :

On Jan 30, 2016, at 1:56 PM, Félix Cloutier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I agree that many closures are expected to be executed only once, but it seems to me that it's only useful to the compiler if it's also marked @noescape. A completion handler marked "once" without "noescape" doesn't allow the compiler to determine that a variable will have been initialized after the call that takes the closure.

So in these other cases, it only serves as documentation. I'm not very enthusiastic about attributes that only serve as documentation because there is an infinity of attributes that can be added to the language for documentation purposes.

It also serves as a guarantee that the closure is executed exactly once. Even if the compiler can’t use it for optimization the guarantee could be useful.

There are other places than `dispatch_sync` where you may want a `@noescape(once)` attribute. Any function that executes a closure while providing some sort of guarantee/RAII-like handle can benefit from it. Most of the functions starting with `with` in the standard library could benefit from it: withExtendedLifetime, withUnsafePointer and friends, withVaList. String's `withCString` and `withMutableCharacters` could benefit from it too. Someone who writes a `withLock(lock) { closure }` function would be happy to have it too.

Félix

Le 30 janv. 2016 à 07:11:23, Rod Brown <rodney.brown6@icloud.com <mailto:rodney.brown6@icloud.com>> a écrit :

I'm very supportive of this type of proposal.

I do agree with Brent though that @noescape and 'once' is somewhat orthogonal.

There are a lot of places where you want to be clear that the block will be called but no more than once. For example, the NSURLSession callback blocks you would expect never to be called multiple times. Completion handlers are almost always used only once. I don't think this case, which is extremely common, can be overlooked.

On the other hand, I suspect the majority of places you use closures with @noescape, it seems more likely you'd want it used multiple times, like a search, filter, find etc of multiple items in a collection or group, otherwise you'd generally just put the closured activity before or after. The only areas where I would expect to see such closures of @noescape and 'once' would be dispatch_sync, or somewhere where you want to invoke custom code in the middle of a complex operation of a method.

It seems to me that separating them, but allowing them to be used together, makes more sense.

Rod

On 30 Jan 2016, at 5:05 AM, Félix Cloutier via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I don't have much to add but I also think that it would be nice to have.

Félix

Le 29 janv. 2016 à 12:38:01, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

On Jan 29, 2016, at 12:23 AM, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I've wanted something like this as well. I think it would be harder than it seems, because "x = 1" might need to perform initialization, or assignment, depending how it's used.

It could make sense to have something like "@noescape(executed_exactly_once)" but this might be so limited it's not worth it. And I'm not sure how it should interact with throws.

I think that something like this is implementable, and making it a modifier to @noescape is sensible.

The semantics we could support is that the function is guaranteed to call the closure exactly once on any path that could lead to a return or throw.

This approach allows you to pass the closure down the stack, and composes with error handling. It is obviously limited what you can do with the closure, but that is necessary to validate correctness.

-Chris

Jacob

On Thu, Jan 28, 2016 at 11:38 PM, Gwendal Roué <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Hello,

I’d like to discuss the opportunity to let functions declare that a closure argument is guaranteed to have been executed when the function has returned.

For example:

  func f(@noescape(executed) closure: () -> ()) {
      closure()
  }

The expected advantage is that the compiler would know that a variable set inside the closure is guaranteed to be initialized, and that it can be used after the execution of the function, as below:

  let x: Int // Not initialized
  f { x = 1 }
  print(x) // Guaranteed to be initialized

Today developers have to write pessimistic code like below:

  var x: Int = 0 // `var` declaration, with some irrelevant value
  f { x = 1 }
  print(x)

As for a real world usage, I’d like to access a database in a safe (queued) way, and fetch values out of it:

  let items: [Item]
  let users: [User]
  dbQueue.inDatabase { db in
      items = Item.all().fetchAll(db)
      users = Item.all().fetchAll(db)
  }

Gwendal Roué

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

+1

I've wanted the ability require that a closure be called for a little while
now. Clean up code is an example of when this can be useful.

···

On Sat, Jan 30, 2016 at 9:54 PM, Félix Cloutier <swift-evolution@swift.org> wrote:

Can the compiler even enforce it? If the closure escapes, it necessarily
means that you assigned it elsewhere. How do you enforce that you never
call this reference more than once?

If the compiler can't take advantage of it and can't enforce it either, I
would rather not have it at all.

I would also think that for a lot of APIs with an escaping closure, it
could be more useful to say that it will be called "at most once" than
"exactly once". Additionally, if completion blocks are the main client of
the feature, I would avoid giving it too much effort before we figure out
the favored concurrency model.

@noescape(once) really looks like a special case to me, because it's
enforceable, useful to the compiler and useful to the user.

Félix

Le 30 janv. 2016 à 15:07:11, Matthew Johnson <matthew@anandabits.com> a
écrit :

On Jan 30, 2016, at 1:56 PM, Félix Cloutier via swift-evolution < > swift-evolution@swift.org> wrote:

I agree that many closures are expected to be executed only once, but it
seems to me that it's only useful to the compiler if it's also marked
@noescape. A completion handler marked "once" without "noescape" doesn't
allow the compiler to determine that a variable will have been initialized
after the call that takes the closure.

So in these other cases, it only serves as documentation. I'm not very
enthusiastic about attributes that only serve as documentation because
there is an infinity of attributes that can be added to the language for
documentation purposes.

It also serves as a guarantee that the closure is executed exactly once.
Even if the compiler can’t use it for optimization the guarantee could be
useful.

There are other places than `dispatch_sync` where you may want a
`@noescape(once)` attribute. Any function that executes a closure while
providing some sort of guarantee/RAII-like handle can benefit from it. Most
of the functions starting with `with` in the standard library could benefit
from it: withExtendedLifetime, withUnsafePointer and friends, withVaList.
String's `withCString` and `withMutableCharacters` could benefit from it
too. Someone who writes a `withLock(lock) { closure }` function would be
happy to have it too.

Félix

Le 30 janv. 2016 à 07:11:23, Rod Brown <rodney.brown6@icloud.com> a écrit
:

I'm very supportive of this type of proposal.

I do agree with Brent though that @noescape and 'once' is somewhat
orthogonal.

There are a lot of places where you want to be clear that the block will
be called but no more than once. For example, the NSURLSession callback
blocks you would expect never to be called multiple times. Completion
handlers are almost always used only once. I don't think this case, which
is extremely common, can be overlooked.

On the other hand, I suspect the majority of places you use closures with
@noescape, it seems more likely you'd *want *it used multiple times, like
a search, filter, find etc of multiple items in a collection or group,
otherwise you'd generally just put the closured activity before or after.
The only areas where I would expect to see such closures of @noescape and
'once' would be dispatch_sync, or somewhere where you want to invoke custom
code in the middle of a complex operation of a method.

It seems to me that separating them, but allowing them to be used
together, makes more sense.

Rod

On 30 Jan 2016, at 5:05 AM, Félix Cloutier via swift-evolution < > swift-evolution@swift.org> wrote:

I don't have much to add but I also think that it would be nice to have.

Félix

Le 29 janv. 2016 à 12:38:01, Chris Lattner via swift-evolution < > swift-evolution@swift.org> a écrit :

On Jan 29, 2016, at 12:23 AM, Jacob Bandes-Storch via swift-evolution < > swift-evolution@swift.org> wrote:

I've wanted something like this as well. I think it would be harder than
it seems, because "x = 1" might need to perform initialization, or
assignment, depending how it's used.

It could make sense to have something like
"@noescape(executed_exactly_once)" but this might be so limited it's not
worth it. And I'm not sure how it should interact with throws.

I think that something like this is implementable, and making it a
modifier to @noescape is sensible.

The semantics we could support is that the function is guaranteed to call
the closure exactly once on any path that could lead to a return or throw.

This approach allows you to pass the closure down the stack, and composes
with error handling. It is obviously limited what you can do with the
closure, but that is necessary to validate correctness.

-Chris

Jacob

On Thu, Jan 28, 2016 at 11:38 PM, Gwendal Roué <swift-evolution@swift.org> > wrote:

Hello,

I’d like to discuss the opportunity to let functions declare that a
closure argument is guaranteed to have been executed when the function has
returned.

For example:

func f(@noescape(executed) closure: () -> ()) {
    closure()
}

The expected advantage is that the compiler would know that a variable
set inside the closure is guaranteed to be initialized, and that it can be
used after the execution of the function, as below:

let x: Int // Not initialized
f { x = 1 }
print(x) // Guaranteed to be initialized

Today developers have to write pessimistic code like below:

var x: Int = 0 // `var` declaration, with some irrelevant value
f { x = 1 }
print(x)

As for a real world usage, I’d like to access a database in a safe
(queued) way, and fetch values out of it:

let items: [Item]
let users: [User]
dbQueue.inDatabase { db in
    items = Item.all().fetchAll(db)
    users = Item.all().fetchAll(db)
}

Gwendal Roué

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

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

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

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

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

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

Yes, I agree. Very good points.

+1

···

On 31 Jan 2016, at 8:55 AM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 30, 2016, at 12:19 PM, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org> wrote:

The "noescape + exactly once" guarantee is useful to the compiler because it allows the closure to *initialize* variables that it captures. The way to think about this is that the closure body is effectively inlined.

"noescape, but not exactly once" is still useful because you can omit references to self, and know that variable modifications in the closure will be visible after the function call. But you can't perform initialization (because the closure might be called more than once), nor can you be sure variables are initialized after the function call (because the closure might not be called at all).

"exactly once, but escaping" is an important API contract that should be documented, but if the closure can escape the call, then you still can't perform initialization in the closure, because the order it happens in w.r.t. the function call isn't guaranteed. I might be missing something, but I don't see any reason for this feature to exist, because...well, it isn't really a feature if it can't do anything.

+1, exactly right.

-Chris
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

The combination of noescape+once is something the compiler can enforce, and because of that, it can provide improved initialization flexibility (and help make things like autoreleasepool feel more statement like).

The combination of escaping+once is not something the compiler can enforce, and becomes of that, it is little more than documentation. I’m a huge fan of documentation, but building it into the language like this would mislead people into thinking it IS enforced by the compiler. Also, this is not how we would build a documentation feature.

The main practical use I imagine this for is completion parameters. These should always be called exactly once, but it's all too easy to write one of these:

  if cantActuallyDoThis() {
    completion(.CantDoThisError)
    // forgot to return
  }
  guard doThing() else {
    return
    // forgot to call completion
  }

If a parameter is marked `@once`, but there are paths where it is executed twice or zero times, Swift ought to be able to detect that and emit an error. It can also assume that, if the parameter is called once within another closure, and *that* closure is passed to an `@once` parameter, it will be called once. A smart overlay on libdispatch could mark its APIs in appropriate places, and in general, the Clang importer could mark any parameter marked "completion" or "completionHandler" as `@once`. That would mark a large and useful subset of the frameworks.

If the parameter is called within a closure that's passed non-once, it's undecidable; it might be called zero, one, or many times. You could just complain about it, or you could do the analysis both ways, and if neither of them yields `@once`-compliant behavior, give a yell.

···

--
Brent Royal-Gordon
Architechies

I'd like to pitch this proposal to implement the feature: https://github.com/zneak/swift-evolution/blob/master/proposals/00xx-noescape-once.md

Rationale for some points:

Only one closure parameter can be marked as @noescape(once) in a function signature.

The attribute doesn't specify the order of execution of the closures, so it could have unintended consequences if closure B depends on closure A but closure B is called first. Given the typical use case (the @noescape(once) closure as a trailing closure), I don't think that it's worth it to invest a lot of effort into coming up with a model to decide (and enforce) which closure has to be called first and what to do if either closure throws or something.

it is not required to be executed on a code path that throws;

It may need to be clarified into "must" or "must not", but I can't think about very good examples supporting either case right now.

Félix

···

Le 30 janv. 2016 à 19:54:19, Rod Brown via swift-evolution <swift-evolution@swift.org> a écrit :

Yes, I agree. Very good points.

+1

On 31 Jan 2016, at 8:55 AM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 30, 2016, at 12:19 PM, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org> wrote:

The "noescape + exactly once" guarantee is useful to the compiler because it allows the closure to *initialize* variables that it captures. The way to think about this is that the closure body is effectively inlined.

"noescape, but not exactly once" is still useful because you can omit references to self, and know that variable modifications in the closure will be visible after the function call. But you can't perform initialization (because the closure might be called more than once), nor can you be sure variables are initialized after the function call (because the closure might not be called at all).

"exactly once, but escaping" is an important API contract that should be documented, but if the closure can escape the call, then you still can't perform initialization in the closure, because the order it happens in w.r.t. the function call isn't guaranteed. I might be missing something, but I don't see any reason for this feature to exist, because...well, it isn't really a feature if it can't do anything.

+1, exactly right.

-Chris
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

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

Thank you very much, Félix!

Gwendal

···

Le 31 janv. 2016 à 07:17, Félix Cloutier via swift-evolution <swift-evolution@swift.org> a écrit :

I'd like to pitch this proposal to implement the feature: https://github.com/zneak/swift-evolution/blob/master/proposals/00xx-noescape-once.md

Rationale for some points:

Only one closure parameter can be marked as @noescape(once) in a function signature.

The attribute doesn't specify the order of execution of the closures, so it could have unintended consequences if closure B depends on closure A but closure B is called first. Given the typical use case (the @noescape(once) closure as a trailing closure), I don't think that it's worth it to invest a lot of effort into coming up with a model to decide (and enforce) which closure has to be called first and what to do if either closure throws or something.

it is not required to be executed on a code path that throws;

It may need to be clarified into "must" or "must not", but I can't think about very good examples supporting either case right now.

Félix

Le 30 janv. 2016 à 19:54:19, Rod Brown via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> a écrit :

Yes, I agree. Very good points.

+1

On 31 Jan 2016, at 8:55 AM, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jan 30, 2016, at 12:19 PM, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

The "noescape + exactly once" guarantee is useful to the compiler because it allows the closure to *initialize* variables that it captures. The way to think about this is that the closure body is effectively inlined.

"noescape, but not exactly once" is still useful because you can omit references to self, and know that variable modifications in the closure will be visible after the function call. But you can't perform initialization (because the closure might be called more than once), nor can you be sure variables are initialized after the function call (because the closure might not be called at all).

"exactly once, but escaping" is an important API contract that should be documented, but if the closure can escape the call, then you still can't perform initialization in the closure, because the order it happens in w.r.t. the function call isn't guaranteed. I might be missing something, but I don't see any reason for this feature to exist, because...well, it isn't really a feature if it can't do anything.

+1, exactly right.

-Chris
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

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

What is the implication of this @noescape(once) closure not being call on throws when the caller use try? variation? Looks like the compiler will have to assume that the @escape(once) is both not called and not not called (sorry for the double-negative). For the try!, i think that the compiler could assume that the @escape(none) is called, as the process would crash otherwise anyway on the throw.

    var bad: Bool = true
    enum e: ErrorType {
        case Simple
    }
    func f(@noescape closure: () -> ()) throws {
        if (bad) { throw e.Simple }
        closure()
    }
    let x: Int // Not initialized
    try? f { x = 1 }
    print(x) // May still be uninitialized, compiler must generate error
    x = 2 // May have been initialized, compiler must generate error

This should probably be highlighted in the proposal as an intended limitation for the typical usage.
Another special case with try? that people may be unlikely to use, is:

    func g(@noescape closure: () -> ()) throws -> Int {
        if (bad) { throw e.Simple }
        closure()
        return 1
    }
    if let data = try? g({ x = 1 }) {
        print(x) // Guaranteed to be initialized
    }
    print(x) // May still be uninitialized, compiler must generate error
    x = 2 // May have been initialized, compiler must generate error

Not sure if this case will make the implementation more complex, it is why I’m mentioning it.

Dany

···

Le 31 janv. 2016 à 01:17, Félix Cloutier via swift-evolution <swift-evolution@swift.org> a écrit :

I'd like to pitch this proposal to implement the feature: https://github.com/zneak/swift-evolution/blob/master/proposals/00xx-noescape-once.md

Rationale for some points:

Only one closure parameter can be marked as @noescape(once) in a function signature.

The attribute doesn't specify the order of execution of the closures, so it could have unintended consequences if closure B depends on closure A but closure B is called first. Given the typical use case (the @noescape(once) closure as a trailing closure), I don't think that it's worth it to invest a lot of effort into coming up with a model to decide (and enforce) which closure has to be called first and what to do if either closure throws or something.

it is not required to be executed on a code path that throws;

It may need to be clarified into "must" or "must not", but I can't think about very good examples supporting either case right now.