SE-0269: Increase availability of implicit self in @escaping closures when reference cycles are unlikely to occur

The review of SE-0269: Increase availability of implicit self in @escaping closures when reference cycles are unlikely to occur begins now and runs through November 12, 2019.

The proposal is written by @Jumhyn.

Reviews are an important part of the Swift evolution process. All review feedback should be either on this forum thread or, if you would like to keep your feedback private, directly to me as the review manager via email or direct message on the forums. If you send me email, please put "SE-0269" somewhere in the subject line.

What goes into a review of a proposal?

The goal of the review process is to improve the proposal under review through constructive criticism and, eventually, determine the direction of Swift.

When reviewing a proposal, here are some questions to consider:

  • 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?

Thank you for contributing to Swift!

Ted Kremenek
Review Manager

26 Likes

Would we be able to expand it to include the case where weak self is rebound to strong self?

execute { [weak self] in
  guard let self = self else { ... }

  // here
}
3 Likes

I think that would be a reasonable extension of this idea, but IMO it would require some more careful design consideration. E.g., would implicit self be available inside an if let self = self block, or only when self is re-bound at the top level? What if you just did let self = self!? I think adding a section about more general self rebinding to Future Directions would be a good idea, though—I’ll do that.

4 Likes

This is great! I appreciate the thought given to all of the edge cases here.

I'd personally like to see the existing fix-it eliminated as part of this proposal as suggested in the alternatives considered section. Including both the old and new fix-its could get noisy, and imo it would be good to push this new style of signaling self capture as the preferred option.

when reference cycles are unlikely to occur

Is it possible to create reference cycle with value-type?

1 Like

+1

I'm a strong proponent for simplifying syntax for @escaping closures. IMO there's still room for improvement there, but I haven't seen a clearly "right" solution.

This proposal removed a redundancy pain point with no syntax changes or additions to the language. Complete win in my book!

1 Like

If the value type contains references, then yes!

3 Likes

I see. Still, in that case value-type in capture list still wouldn't help fixing that, would it?

Guess my ultimate question is, what is the scenario one would want to put value-type in capture list?. Since that would be what interfere with the latter part of the proposal.

SE-0269: Yes, please.

I think that declaring capture list as the preferred option need more discussion.
I don't see it as a win for simple closures.

foo { self.bar() }

vs

foo { [self] in
  bar()
}
1 Like

+1 and maybe suggest self. as a fixit only for single-expression closures instead of [self] in?

1 Like

So I dislike this, but only because I dislike implicit self. I am aware that my dislike of implicit self puts me in a minority of the Swift community, but regardless, I would rather not see it further propagated. I have no particular problem with any of the rest of the pitch, so if the consensus of the community is that implicit self is great then I won’t try to stand in the way.

16 Likes

I’m not sure that “single expression” is necessarily the best heuristic, since you could have something like

foo {
    bar(with: thing1, and: thing2)
}

Where the suggested fix-it would be:

foo {
    self.bar(with: self.thing1, and: self.thing2)
}

Perhaps “single use of implicit self” would be a better test, but I’d still rather introduce both with this proposal and see a follow-up proposal/bugfix that improves the diagnostic logic.

5 Likes

Yes to the proposal. This would eliminate unexpected self. pollution of code that would otherwise be written without self. when outside escaping closures. Which was an annoyance from the first days of Swift.

Thank you @Jumhyn for the thought and work put into this.


Side note to future proposals: this one originated from the observation that "explicit capture semantics" is not explicit. self.foo() have no indicators whether self is captured or not – you need to know its context. This leads to a) pollution with unexpected self. to silence compiler errors; b) no support for projects adopting self. on every member access.

1 Like

FWIW, @lukasa, I have in the past felt similarly about implicit self, but part of that was precisely because of the annoyance addressed by this proposal—highly event-driven codebases which wanted to use implicit self could only do so inconsistently (which I made a note of in the proposal).

That said, even if one takes a principled stand against the use of implicit self, I don't think that enforcing arbitrary restrictions on its use makes for good language design. E.g. even if I hypothetically felt like "Eliminate implicit self" were a worthwhile proposal, I probably wouldn't support a proposal of the form "Eliminate implicit self for property references, but not method references" solely based on the argument that it came closer to my ideal. So though I'm sympathetic to concerns about the use of implicit self, I think that those concerns are somewhat orthogonal to increasing the consistency and simplicity of the rules surrounding implicit self (and probably better enforced by a style guide/linter).

4 Likes

To be clear, I agree that partial removal of implicit self is not sensible: it should be acceptable broadly or not at all. My objection (which I hope was clearly a very weak objection) was only that expanding the availability of implicit self is moving the curve in the opposite direction of my preferred one. :grin:

3 Likes

I am neutral on this because the current behavior is simple enough to explain. Introducing nuance here doesn't seem like a huge win.

I'd still use the capture list in that example for consistency even though it's more characters, but it's definitely a subjective thing.

FWIW I think I agree. IMO a capture list is a much better indication to (especially new) users that something different is happening here. The current Implicit self capture feels like an odd compiler constraint that means "oh I guess I have to use self here for some reason".

9 Likes
  • What is your evaluation of the proposal?

I'm neutral on the first part of the proposal as proposed. It's reasonable in the cases where it works. But there isn't an obvious way to support weak captures so it doesn't replace the current syntax either.

I have some concerns about the second part of the proposal. If it could be limited to value semantics it would make sense to me. But it can't, it is possible to store references in a value type, therefore making reference cycles possible without any explicit indication of the capture.

If the first part of the proposal is accepted value types would already be able to explicitly capture [self] rather than writing self. everywhere. This might be enough sugar for this use case and does not have the potential to introduce cycles without indication of the capture. It also significantly strengthens the argument for accepting the first part of the proposal if the second part is left off, as it significantly widens the use cases for the first part fo the proposal.

Overall, I think this proposal is a tough judgement call. I don't have a firm opinion, but my instinct is that we might be better off if only one part is accepted. Having either one in the language weakens the motivation for the other IMO. On balance, I think the first part of the proposal has the strongest motivation.

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

Possibly? I trust the core team to decide on this.

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

IMO, the first part fits better than the second.

  • 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?

A quick read, followed by consideration of the tradeoffs involved.

6 Likes