[Review] SE-0103: Make non-escaping closures the default

Hello Swift community,

The review of "SE-0103: Make non-escaping closures the default" begins now and runs through June 27. The proposal is available here:

  swift-evolution/0103-make-noescape-default.md at master · apple/swift-evolution · GitHub

Reviews are an important part of the Swift evolution process. All reviews should be sent to the swift-evolution mailing list at

  https://lists.swift.org/mailman/listinfo/swift-evolution

or, if you would like to keep your feedback private, directly to the review manager.

What goes into a review?

The goal of the review process is to improve the proposal under review through constructive criticism and contribute to the direction of Swift. When writing your review, here are some questions you might want to answer in your review:

  * What is your evaluation of the proposal?
  * Is the problem being addressed significant enough to warrant a change to Swift?
  * Does this proposal fit well with the feel and direction of Swift?
  * If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
  * How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

More information about the Swift evolution process is available at

  swift-evolution/process.md at master · apple/swift-evolution · GitHub

Thank you,

-Chris Lattner
Review Manager

  * What is your evaluation of the proposal?

+1 I think this will help getting safer code by default along with already approved SE-0035 <https://github.com/apple/swift-evolution/blob/master/proposals/0035-limit-inout-capture.md&gt;

  * Is the problem being addressed significant enough to warrant a change to Swift?

Yes. I think that @nonescaping is a good default that goes along the same lines on why I use `let` over `var.
When I learned about @nonescaping I found myself using it more and more but it felt like having to use `const` in C++ and I thought why isn’t @noscape the default.
I think that is @nonescaping was available before swift 1 came out that the core team would have made it the default.

How would somebody unsafely cast an escaping closure to a non escaping? Do we need to keep the @nonescaping attribute around for this to work?

  * Does this proposal fit well with the feel and direction of Swift?

Yes. Safe by default.

  * If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

n/a

  * How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

Follow the discussing and proposal.

* What is your evaluation of the proposal?

My team just started using Swift a few weeks ago. But based on my
experience in Objective-C and problems with retain cycles I really
really like this proposal. Makes the code easier to grasp because by
just reading it I know that that closure cannot escape by default, so
the receiver will not hold onto to it for longer than I expect.

I totally approve this change. Sounds awesome.

* Is the problem being addressed significant enough to warrant a
  change to Swift?

Based on my experience using blocks and async callbacks in Objective-C,
yes. I expect Swift to be safe by default and this helps solving a
common problem for me.

* Does this proposal fit well with the feel and direction of Swift?

Yes, safe by default. Without being hard to use.

* If you have used other languages or libraries with a similar
  feature, how do you feel that this proposal compares to those?

N/A

* How much effort did you put into your review? A glance, a quick
  reading, or an in-depth study?

I read the proposal.

  * What is your evaluation of the proposal?

I’m strongly in favor - improvements on retain cycle issues are a huge win, and escaping as the default better fits the visual layout of the code and forces the developer to think more for the case that’s more conceptually complicated instead of the simple one. The way I read it also suggests that the compiler will be able to give better warnings with nonescaping as the default, and better warnings are rarely a bad thing :). I also like the normalization of the otherwise somewhat awkward and redundant @autoclosure(escaping) syntax - with nonescaping as the default, this is no longer a place where there’s a disconnect between closure behaviors in different contexts.

  * Is the problem being addressed significant enough to warrant a change to Swift?

Definitely; retain cycles are bad enough without making them more painful than they need to be, matching the code’s behavior to its appearance is a net win for ease of use, and the removal of the @autoclosure(escaping) syntax cleans up a place where the language often looks as if it’s deliberately being pedantic in a context where the intent is obvious.

  * Does this proposal fit well with the feel and direction of Swift?

I couldn’t imagine a better fit - an improvement to syntax, intent, consistency, and behavior all at once; being able to make such improvements is one of the fundamental essences of Swift (at least as I understand it :).

  * If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

I haven’t used any languages which have a similar feature, unless you count Objective-C and its lack of a "nonescaping" syntax (or concept) for blocks (I imagine Clang has code to optimize them when it does detect them, but it definitely wasn't part of the blocks spec last time I read it.) Speaking from that experience and what I’ve done with closures in Swift, I definitely like being able to declare explicitly that my closure doesn’t escape; it clarifies my intent without needing extra text in my headerdocs explaining the block’s semantics. I like it even better with nonescaping as the default - consumers of my API (including myself) don’t have to think nearly as hard about retain cycles in a surprising number of cases (I obviously don’t do much Objective-C bridging ^^; )

  * How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

I gave it a moderate amount of attention; I haven’t done deep research or refreshed my memory of the semantics further than a quick skim, but I don’t think there are many corner cases that need consideration for this proposal (which is another reason I like it and the way proposals in Swift are done in general). (Also, I generally trust my memory for semantics I was working with successfully an hour ago :)

-- Gwynne Raskind

The review of "SE-0103: Make non-escaping closures the default" begins now and runs through June 27. The proposal is available here:

  https://github.com/apple/swift-evolution/blob/master/proposals/0103-make-noescape-default.md

  * What is your evaluation of the proposal?

Huge +1. I think this will lead to safer, faster code by default and better errors and warnings.

  * Is the problem being addressed significant enough to warrant a change to Swift?

Yes.

  * Does this proposal fit well with the feel and direction of Swift?

Yes.

  * If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

n/a

  * How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

Followed the discussion, read the proposal twice.

l8r
Sean

  * What is your evaluation of the proposal?

+11. This is a much better default. Escaping closures impose additional complexity on callers which should only be introduced when necessary.

I am extremely unconvinced by the primary opposing argument that it should not be a breaking change to escape a closure that was not previously escaping. This is a significant semantic change. If an API author wants to reserve the right to escape a closure they should explicitly opt-in to that semantic from the start.

  * Is the problem being addressed significant enough to warrant a change to Swift?

Yes. Unfortunately many programmers are not careful about providing annotations that are not strictly required by the compiler. This means that the compiler currently must treat many closures as escaping even though they will never actually escape. This change makes the language safer and easier to use.

  * Does this proposal fit well with the feel and direction of Swift?

Very much so.

  * If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

No.

  * How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

I followed and participated in the discussion and gave the final proposal a quick read. I have always thought this is the right default for the language and am glad to see that this proposal is receiving positive feedback.

   * What is your evaluation of the proposal?

+1. It's a positive change. It makes un-annotated code safer, and it moves the annotation to the case where one needs to think about captures as opposed to annotating the case where one doesn't have to think about captures.

   * Is the problem being addressed significant enough to warrant a change to Swift?

Yes. It both helps in the un-annotated cases and it adds explicit annotation for escaping closures which serve as a documentation that one need to think about how variables are captured when invoking these functions/methods.

   * Does this proposal fit well with the feel and direction of Swift?

Yes. It's goes with the safer of the two choices by default. I also imagine that it might be ever so slightly more performant I these cases.

   * If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

I've not used another language that explicitly makes a distinction between escaping and non-escaping.

Objective-C blocks always capture everything, which has led to a common "weakify/strongify dance" in most cases, even in cases where there wasn't a cycle.

   * How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

Read the proposal, skimmed thought the discussion, and a little experimentation with the current syntax.

- David

···

On 22 Jun 2016, at 07:03, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

Hello Swift community,

The review of "SE-0103: Make non-escaping closures the default" begins now and runs through June 27. The proposal is available here:

   https://github.com/apple/swift-evolution/blob/master/proposals/0103-make-noescape-default.md

Reviews are an important part of the Swift evolution process. All reviews should be sent to the swift-evolution mailing list at

   https://lists.swift.org/mailman/listinfo/swift-evolution

or, if you would like to keep your feedback private, directly to the review manager.

What goes into a review?

The goal of the review process is to improve the proposal under review through constructive criticism and contribute to the direction of Swift. When writing your review, here are some questions you might want to answer in your review:

   * What is your evaluation of the proposal?
   * Is the problem being addressed significant enough to warrant a change to Swift?
   * Does this proposal fit well with the feel and direction of Swift?
   * If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
   * How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

More information about the Swift evolution process is available at

   https://github.com/apple/swift-evolution/blob/master/process.md

Thank you,

-Chris Lattner
Review Manager

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

  * What is your evaluation of the proposal?

I support it; if escaping and nonescaping are about equally common, but users would never discover a @nonescaping on their own, I think it makes sense to have @escaping instead.

However, I'm concerned about migration. Rather than saying that all currently escaping closures will be marked with @escaping, the proposal says:

Existing code using the @noescape attribute will need to be migrated to remove the attribute since it will be the default. In addition, the compiler will need to detect escaping closures that are not marked with @escaping and create an error with a fixit to add the required attribute.

If I'm reading this correctly, it's saying that the migrator will convert *all* closures into nonescaping closures and then let compiler errors guide the user to convert those that need to escape. This is going to add to the burden of migrating code to Swift 3. And the compiler may not catch all mistakes—consider, for instance, a framework which defines a public delegate protocol with a method that takes a completion or reply closure. That parameter probably ought to be @escaping, but if it's not, nothing in the module itself will break.

I think it would be better if the migrator added @escaping to all currently-non-@noescape closures, thus preserving current semantics. The cost of doing so—forgoing a speed improvement—is just not that large. And I can just imagine the tableflip I would do if I were assigned to migrate, say, Alamofire to Swift 3 and it forced me to manually annotate *every* closure parameter in the entire library.

Failing that, I would consider at least doing so on public methods of protocols and nonfinal classes, where the concerns are most acute. I would also like to see the migrator automatically add @escaping to closure parameters it heuristically determines are probably escaping—at the very least, `completion` and `completionHandler` trailing closures.

  * Is the problem being addressed significant enough to warrant a change to Swift?

Yes.

  * Does this proposal fit well with the feel and direction of Swift?

Yes. @noescape was just weird.

  * If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

None I can think of, unless Objective-C is somehow doing this behind my back.

  * How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

Quick reading.

···

--
Brent Royal-Gordon
Architechies

** What is your evaluation of the proposal?*

-1

I find myself using 3 types of closures:
- Algorithm-like (filter, map etc.). non-escaping
- Completion closures: asynchronous operations: network requests, many
cocoa APIs, background image processing. escaping
- Data/dependency providers: userProvider(forId id: String) -> User.
escaping (ok, can be non-escaping sometimes too)

In the codebases I'm working with, escaping closures predominate clearly;
and most of the non-escaping ones refer to usages of the standard library.

Another point comes when changing things. Consider the following code:

func doSomething(closure: () -> Void) {
self.doSomething2(closure)
}

func doSomething2(closure: () -> Void) {
self.doSomething3(closure)
}

func doSomething3(closure: () -> Void) {
closure()
}

If non-escaping is the default, and for some reason doSomething3's closure
needs to change to escaping, then I would have to change all the callers as
escaping.

To sump up, I see @noescape as something to opt-in for performance reasons
(or better static analysis as it was mentioned during the initial
discussion) but I don't think it's a good default.

** Is the problem being addressed significant enough to warrant a change to
Swift?*
I don't think there's a problem that needs to be fixed.

** Does this proposal fit well with the feel and direction of Swift?*
Not really. I think escaping is a safe good default that works for all
cases.

** If you have used other languages or libraries with a similar feature,
how do you feel that this proposal compares to those?*
NA

** How much effort did you put into your review? A glance, a quick reading,
or an in-depth study?*
Followed the discussion and read the proposal carefully.

···

2016-06-22 6:03 GMT+01:00 Chris Lattner via swift-evolution < swift-evolution@swift.org>:

Hello Swift community,

The review of "SE-0103: Make non-escaping closures the default" begins now
and runs through June 27. The proposal is available here:

https://github.com/apple/swift-evolution/blob/master/proposals/0103-make-noescape-default.md

Reviews are an important part of the Swift evolution process. All reviews
should be sent to the swift-evolution mailing list at

        https://lists.swift.org/mailman/listinfo/swift-evolution

or, if you would like to keep your feedback private, directly to the
review manager.

What goes into a review?

The goal of the review process is to improve the proposal under review
through constructive criticism and contribute to the direction of Swift.
When writing your review, here are some questions you might want to answer
in your review:

        * What is your evaluation of the proposal?
        * Is the problem being addressed significant enough to warrant a
change to Swift?
        * Does this proposal fit well with the feel and direction of Swift?
        * If you have used other languages or libraries with a similar
feature, how do you feel that this proposal compares to those?
        * How much effort did you put into your review? A glance, a quick
reading, or an in-depth study?

More information about the Swift evolution process is available at

        https://github.com/apple/swift-evolution/blob/master/process.md

Thank you,

-Chris Lattner
Review Manager

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

-1 for the proposal too

@nonescaping is more restrictive than escaping closure. You can’t pass a non escaping closure to a method that expects one, while the reverse is possible.

Nowadays, a method without any annotation defaults to be able to do anything. If we switch to non-escaping as the default, a method without annotation would be restricted in what it can do with the closure. That’s why I don’t think this is a good move.

for example:

func myfunc(closure: () -> Void) {
  stdlibfunction(closure)
}

Today, whatever the stdlib function annotation is, it will compile. By reversing the annotation, that code may compile or not depending the stdlib function annotation.

Forcing the newcomer to learn advanced optimization technic to be able to write a simple function is very bad IMHO.

···

Le 23 juin 2016 à 23:06, Diego Sánchez via swift-evolution <swift-evolution@swift.org> a écrit :

* What is your evaluation of the proposal?

-1

I find myself using 3 types of closures:
- Algorithm-like (filter, map etc.). non-escaping
- Completion closures: asynchronous operations: network requests, many cocoa APIs, background image processing. escaping
- Data/dependency providers: userProvider(forId id: String) -> User. escaping (ok, can be non-escaping sometimes too)

In the codebases I'm working with, escaping closures predominate clearly; and most of the non-escaping ones refer to usages of the standard library.

Another point comes when changing things. Consider the following code:

func doSomething(closure: () -> Void) {
  self.doSomething2(closure)
}

func doSomething2(closure: () -> Void) {
  self.doSomething3(closure)
}

func doSomething3(closure: () -> Void) {
  closure()
}

If non-escaping is the default, and for some reason doSomething3's closure needs to change to escaping, then I would have to change all the callers as escaping.

To sump up, I see @noescape as something to opt-in for performance reasons (or better static analysis as it was mentioned during the initial discussion) but I don't think it's a good default.

* Is the problem being addressed significant enough to warrant a change to Swift?
I don't think there's a problem that needs to be fixed.

* Does this proposal fit well with the feel and direction of Swift?
Not really. I think escaping is a safe good default that works for all cases.

* If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
NA

* How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
Followed the discussion and read the proposal carefully.

2016-06-22 6:03 GMT+01:00 Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:
Hello Swift community,

The review of "SE-0103: Make non-escaping closures the default" begins now and runs through June 27. The proposal is available here:

        https://github.com/apple/swift-evolution/blob/master/proposals/0103-make-noescape-default.md

Reviews are an important part of the Swift evolution process. All reviews should be sent to the swift-evolution mailing list at

        https://lists.swift.org/mailman/listinfo/swift-evolution

or, if you would like to keep your feedback private, directly to the review manager.

What goes into a review?

The goal of the review process is to improve the proposal under review through constructive criticism and contribute to the direction of Swift. When writing your review, here are some questions you might want to answer in your review:

        * What is your evaluation of the proposal?
        * Is the problem being addressed significant enough to warrant a change to Swift?
        * Does this proposal fit well with the feel and direction of Swift?
        * If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
        * How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

More information about the Swift evolution process is available at

        https://github.com/apple/swift-evolution/blob/master/process.md

Thank you,

-Chris Lattner
Review Manager

_______________________________________________
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