Proposal: Allow `[strong self]` capture in closures and remove the `self` requirement therein

+1, a lot better than needing to put self in front of everything.

···

On 23 Jan 2016, at 8:26 PM, Marc Knaup via swift-evolution <swift-evolution@swift.org> wrote:

Is the self requirement when using [self] capture still necessary once the limitations outlined by Chris Lattner are solved?
Or does this change still have to go through Swift Evolution?

On Fri, Dec 18, 2015 at 1:21 AM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:
FWIW, I’m also +1 on this proposal, but it should just be a capture list of [self], since all captures are strong by default. This is also part of the intended design of capture lists. The only reason we don’t do this already is that there are some implementation limitations (aka, hacks) around name lookup of “self" that need to be unraveled.

-Chris

> On Dec 17, 2015, at 2:20 PM, Rudolf Adamkovic via swift-evolution <swift-evolution@swift.org> wrote:
>
> +1
>
> I've been writing a lot of experimental UIKit animation code past couple of days and spent most of my time adding and removing "self".
>
> R+
>
> Sent from my iPhone
>
>> On 16 Dec 2015, at 00:02, Greg Parker via swift-evolution <swift-evolution@swift.org> wrote:
>>
>> Swift currently requires that `self` be used explicitly inside closures, to help avoid bugs from unintentional capture. This is annoying when a closure uses `self` a lot. Closures should be allowed to name `[strong self]` in their capture list and thereafter not be required to write `self` everywhere.
>>
>> I wrote code this weekend that looked something like this:
>>
>> data = ...
>> running = true
>> delegate.notifyBegin(data)
>>
>> dispatch_async(queue) {
>> self.processData(self.data)
>> self.running = false
>> self.delegate.notifyEnd(self.data)
>> }
>>
>> Note the asymmetry: the dispatched code needs to use `self` and the non-dispatched code does not. It is clear that the dispatched closure captures `self`, but it's annoying that it needed to be mentioned five different times. The noise gets worse with longer closures. The annoyance gets worse when moving code in and out of dispatches or other closures, with lots of editing required each time.
>>
>> The proposal would allow the same code to be written like this:
>>
>> data = ...
>> running = true
>> delegate.notifyBegin(data)
>>
>> dispatch_async(queue) {
>> [strong self] in
>> processData(data)
>> running = false
>> delegate.notifyEnd(data)
>> }
>>
>> Advantages:
>> * The dispatch'ed code looks like the non-dispatched code.
>> * The capture of `self` is still obvious.
>> * The code's action is clearer without the `self` noise.
>>
>> Disadvantages:
>> * The capture behavior of self's properties is less obvious. For example, neither closure above captured its own copy of `self.data`, but that behavior is not immediately visible in the second closure.
>>
>>
>> What about [weak self] and [unowned self] ? I do not propose to change the `self` requirement for those closures. In the weak case it is critically important to know where `self` is accessed, because it could potentially become nil between any two accesses. Unowned self might be reasonable to change, but for simplicity I won't do so here.
>>
>>
>> --
>> Greg Parker gparker@apple.com Runtime Wrangler
>>
>>
>> _______________________________________________
>> 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

dispatch_semaphore_wait never returns and thus the current scope is never
left. This is likely what keeps the Photo instance alive.

···

On Wed, Dec 16, 2015 at 2:24 AM, Marc Knaup <marc@knaup.koeln> wrote:

Waiiiit. That looks more like a bug in Swift than expected behavior which
would us prevent [strong self] from being used.

   - metadata is a value type and thus should be copied. There's should
   be no implicit reference back to the Photo instance.
   - Capturing "self" in the closure because a property is accessed is
   fine and intentional. The reference to self would normally be destroyed as
   soon as the closure is gone.

So something must erroneously keep either the closure alive or hold a
reference to self which it shouldn't.

On Wed, Dec 16, 2015 at 2:12 AM, Drew Crawford via swift-evolution < > swift-evolution@swift.org> wrote:

Can you explain what is so evil about func evil() when it is called from
an asynchronously-executed closure?

Apologies for earlier brevity, perhaps it would be helpful for me to
present a more complete, realistic example. Paste the following into
main.swift:

import Foundation

print("Hello, World!")

typealias evilArg = [String:String]
var strongReference: evilArg! = nil
func evil(foo:evilArg ) {
    strongReference = foo
}

final class Photo {
    var data = [UInt8](count: 100000000, repeatedValue: 0) //a large
amount of data
    let metadata: [String: String] = [:] //a small amount of data
    func save() {
        dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0)) {
            evil(self.metadata)
        }
    }
}
let p = Photo()
p.save()
//leaks Photo, data, and metadata

let sema = dispatch_semaphore_create(0)
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER)

In this example, the memory usage at the end of the program is 100MB:

This is because Photo, data, and metadata are all leaked by the evil
function.

This is the (surprising?) behavior specified in the Swift Book:

[A capture occurs when] the closure’s body accesses a property of the
instance, such as self.someProperty, or because the closure calls a method
on the instance, such as self.someMethod(). In either case, these accesses
cause the closure to “capture” self, creating a strong reference cycle.

Even though evil may seem (to the casual programmer who does not read
language specifications for funsies) like the closure captures only the
evil argument `metadata`, it **actually** captures *Photo (and therefore
data)*

The capture of Photo (data) is somewhat clear when we write

evil(self.metadata)

But it is hidden when we write

evil(metadata)

As you propose.

I think that if we are going to have semantics that capture Photo (data),
it had better look like it in a cursory inspection. The existing syntax is
not as great as it could be, but it provides a clue. I think even that the
existing syntax isn't good enough, because I expect that many people are
unaware of this particular dark corner. As you say:

Can you explain what is so evil about func evil() when it is called from
an asynchronously-executed closure? I don't see an obvious bug here.

It may very well be that there is no *obvious* bug, and so what we may
actually need is a proposal to make the programmer even more explicit when
referencing self, not less.

But in any case. For `strong self` to make sense, we would need to do
one of two things:

1. We could change Swift semantics to only capture metadata in this
example, however this is a breaking change, and a very very nontrivial
one. I do not know why it is specified this way in the first place,
perhaps a designer can weigh in on that. I do know that ObjC is very
similar, so there may be compatibility implications.

2. We could introduce additional syntax to provide compiler diagnostics
to guard in this case, e.g.

func lessEvil(@noescape foo:evilArg ) { //@noescape currently not
supported for non-closure parameters
     self.strongReference = foo //should generate diagnostic about
escaping a @noescape parameter
}

and then

dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0)) { [strong
self] in
            evil(metadata) //should generate diagnostic that self is
required for functions without @noescape
            lessEvil(metadata) //no diagnostic since parameter is
@noescape
}

I think both of these fixes to the proposal are fairly impractical, but
they would weaken my vote to -0.5.

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

+1 explicit is better than implicit (capture of self)

This should also be promoted by style guides. It's easy for a novice to
miss that self.property captures the whole self, the capture list is much
more useful in that regard.

···

On Wed, Dec 16, 2015 at 05:06 Matthew Johnson via swift-evolution < swift-evolution@swift.org> wrote:

I believe it has been made clear upthread now, but only the closure is
capturing self. Your evil function only stores a copy of the dictionary.

This behavior is identical whether you use [strong self] and metadata or
you use self.metadata so I don’t understand why it would be an argument
against the proposal. Either way the capture of self by the closure is
explicitly represented in the code where it happens. [strong self]
actually seems a bit more clear to me.

An example that behaves like you stated could be concocted if we modify
your example to pass a bound method rather than a property value, however
that seems pretty unlikely to happen unintentionally even if / when we can
obtain references to bound property getters / setters.

typealias evilArg = [String:String]
var strongReference: () -> evilArg
func evil(foo: () -> evilArg ) {
    strongReference = foo
}

final class Photo {
    var data = [UInt8](count: 100000000, repeatedValue: 0) //a large
amount of data
    func metadata() -> [String: String] { return [:] }

    func save() {
        dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0)) {
            evil(self.metadata)
        }
    }
}

I understand why you’re afraid of anything that might lead to
unintentionally storing a strong reference or creating a reference cycle.
I don’t understand why this proposal is likely to make that happen. I
would even argue it might make it less likely to happen. If developers get
in the habit of using the capture list rather than explicitly using “self.”
in the body they will be more likely to capture only what they need. In
your example the developer may have specified [metadata = self.metadata]
rather than using [strong self] if the metadata value at the time of
closure capture was sufficient.

Matthew

On Dec 15, 2015, at 7:23 PM, Drew Crawford via swift-evolution < > swift-evolution@swift.org> wrote:

On Dec 15, 2015, at 7:15 PM, Greg Parker <gparker@apple.com> wrote:

We could make it more difficult for unaware programmers to *write* the
`[strong self]` version, at least. When a programmer writes just `metadata`
in a closure, the compiler could continue to suggest using `self.metadata`
and not suggest using `[strong self]`.

That's not (especially) the danger I'm worried about.

I'm worried about the case where I write `[strong self] in` and then years
later I add the `evil(f)` to the bottom of the closure, because it turns
out we need more code in there.

I'm also worried about the case where I write nonEvil(f) but at some later
time the implementation of nonEvil(f) becomes evil.

I'm also worried about the case where nonEvil(f) is a call into
closed-source UIKit and without any visibility to me, UIKit's
implementation of nonEvil becomes evil between iOS10b3 and iOS10b4.

These things are "category 5" bugs waiting to happen, and they can't be
competently addressed with a UI-level fix in Xcode.
_______________________________________________
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

Generally speaking, memory management schemes are "shippably fast, deterministic, cycle collecting: pick at most 2". ARC picks 1 and 2, tracing garbage collectors pick 1 and 3.

    David

···

On Jan 23, 2016, at 12:22 PM, Paul Ossenbruggen via swift-evolution <swift-evolution@swift.org> wrote:

I am very sure this is covered elsewhere, could someone point me to a discussion of why we can’t automate the removal of self cycles for closures. Is it because it essentially means that we need a garbage collector? This seems like one of the biggest stumbling blocks for new developers and even experienced developers of iOS. ARC was brilliant in that it eliminated 95% writing code to deal with memory issues, but for this one. What about a solution that just solved this one problem with closures and not a general solution that solved all memory cycles? Is that feasible? The strong and weak is pretty easy to understand everywhere else except the closure case, I know lots of people who don’t fully understand when you need to use weakSelf and strongSelf etc. Anyway, i am sure this has been discussed in depth just want to understand all the issues. Also, this may not be strictly a swift topic.

On Jan 23, 2016, at 9:38 AM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 23, 2016, at 1:26 AM, Marc Knaup <marc@knaup.koeln> wrote:

Is the self requirement when using [self] capture still necessary once the limitations outlined by Chris Lattner are solved?
Or does this change still have to go through Swift Evolution?

Once we have [self] in closures, I think it is obvious that the "self.” requirement would be disabled for any closure that uses it.

-Chris

On Fri, Dec 18, 2015 at 1:21 AM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:
FWIW, I’m also +1 on this proposal, but it should just be a capture list of [self], since all captures are strong by default. This is also part of the intended design of capture lists. The only reason we don’t do this already is that there are some implementation limitations (aka, hacks) around name lookup of “self" that need to be unraveled.

-Chris

> On Dec 17, 2015, at 2:20 PM, Rudolf Adamkovic via swift-evolution <swift-evolution@swift.org> wrote:
>
> +1
>
> I've been writing a lot of experimental UIKit animation code past couple of days and spent most of my time adding and removing "self".
>
> R+
>
> Sent from my iPhone
>
>> On 16 Dec 2015, at 00:02, Greg Parker via swift-evolution <swift-evolution@swift.org> wrote:
>>
>> Swift currently requires that `self` be used explicitly inside closures, to help avoid bugs from unintentional capture. This is annoying when a closure uses `self` a lot. Closures should be allowed to name `[strong self]` in their capture list and thereafter not be required to write `self` everywhere.
>>
>> I wrote code this weekend that looked something like this:
>>
>> data = ...
>> running = true
>> delegate.notifyBegin(data)
>>
>> dispatch_async(queue) {
>> self.processData(self.data)
>> self.running = false
>> self.delegate.notifyEnd(self.data)
>> }
>>
>> Note the asymmetry: the dispatched code needs to use `self` and the non-dispatched code does not. It is clear that the dispatched closure captures `self`, but it's annoying that it needed to be mentioned five different times. The noise gets worse with longer closures. The annoyance gets worse when moving code in and out of dispatches or other closures, with lots of editing required each time.
>>
>> The proposal would allow the same code to be written like this:
>>
>> data = ...
>> running = true
>> delegate.notifyBegin(data)
>>
>> dispatch_async(queue) {
>> [strong self] in
>> processData(data)
>> running = false
>> delegate.notifyEnd(data)
>> }
>>
>> Advantages:
>> * The dispatch'ed code looks like the non-dispatched code.
>> * The capture of `self` is still obvious.
>> * The code's action is clearer without the `self` noise.
>>
>> Disadvantages:
>> * The capture behavior of self's properties is less obvious. For example, neither closure above captured its own copy of `self.data`, but that behavior is not immediately visible in the second closure.
>>
>>
>> What about [weak self] and [unowned self] ? I do not propose to change the `self` requirement for those closures. In the weak case it is critically important to know where `self` is accessed, because it could potentially become nil between any two accesses. Unowned self might be reasonable to change, but for simplicity I won't do so here.
>>
>>
>> --
>> Greg Parker gparker@apple.com Runtime Wrangler
>>
>>
>> _______________________________________________
>> 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

dispatch_semaphore_wait never returns and thus the current scope is never left. This is likely what keeps the Photo instance alive.

OMG, you're totally right

vote adjusted to -0.5

No leak here:

import Foundation

print("Hello, World!")

typealias evilArg = [String:String]
var strongReference: evilArg! = nil
func evil(foo:evilArg ) {
    strongReference = foo
}

final class Photo {
    var data = [UInt8](count: 100000000, repeatedValue: 0) //a large amount
of data
    let metadata: [String: String] = [:] //a small amount of data
    func save() {
        dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0)) {
            evil(self.metadata)
        }
    }
}

do {
    let p = Photo()
    p.save()
}

let sema = dispatch_semaphore_create(0)
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER)

···

On Wed, Dec 16, 2015 at 2:32 AM, Marc Knaup <marc@knaup.koeln> wrote:

dispatch_semaphore_wait never returns and thus the current scope is never
left. This is likely what keeps the Photo instance alive.

On Wed, Dec 16, 2015 at 2:24 AM, Marc Knaup <marc@knaup.koeln> wrote:

Waiiiit. That looks more like a bug in Swift than expected behavior which
would us prevent [strong self] from being used.

   - metadata is a value type and thus should be copied. There's should
   be no implicit reference back to the Photo instance.
   - Capturing "self" in the closure because a property is accessed is
   fine and intentional. The reference to self would normally be destroyed as
   soon as the closure is gone.

So something must erroneously keep either the closure alive or hold a
reference to self which it shouldn't.

On Wed, Dec 16, 2015 at 2:12 AM, Drew Crawford via swift-evolution < >> swift-evolution@swift.org> wrote:

Can you explain what is so evil about func evil() when it is called from
an asynchronously-executed closure?

Apologies for earlier brevity, perhaps it would be helpful for me to
present a more complete, realistic example. Paste the following into
main.swift:

import Foundation

print("Hello, World!")

typealias evilArg = [String:String]
var strongReference: evilArg! = nil
func evil(foo:evilArg ) {
    strongReference = foo
}

final class Photo {
    var data = [UInt8](count: 100000000, repeatedValue: 0) //a large
amount of data
    let metadata: [String: String] = [:] //a small amount of data
    func save() {
        dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0)) {
            evil(self.metadata)
        }
    }
}
let p = Photo()
p.save()
//leaks Photo, data, and metadata

let sema = dispatch_semaphore_create(0)
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER)

In this example, the memory usage at the end of the program is 100MB:

This is because Photo, data, and metadata are all leaked by the evil
function.

This is the (surprising?) behavior specified in the Swift Book:

[A capture occurs when] the closure’s body accesses a property of the
instance, such as self.someProperty, or because the closure calls a method
on the instance, such as self.someMethod(). In either case, these accesses
cause the closure to “capture” self, creating a strong reference cycle.

Even though evil may seem (to the casual programmer who does not read
language specifications for funsies) like the closure captures only the
evil argument `metadata`, it **actually** captures *Photo (and
therefore data)*

The capture of Photo (data) is somewhat clear when we write

evil(self.metadata)

But it is hidden when we write

evil(metadata)

As you propose.

I think that if we are going to have semantics that capture Photo
(data), it had better look like it in a cursory inspection. The existing
syntax is not as great as it could be, but it provides a clue. I think
even that the existing syntax isn't good enough, because I expect that many
people are unaware of this particular dark corner. As you say:

Can you explain what is so evil about func evil() when it is called from
an asynchronously-executed closure? I don't see an obvious bug here.

It may very well be that there is no *obvious* bug, and so what we may
actually need is a proposal to make the programmer even more explicit when
referencing self, not less.

But in any case. For `strong self` to make sense, we would need to do
one of two things:

1. We could change Swift semantics to only capture metadata in this
example, however this is a breaking change, and a very very nontrivial
one. I do not know why it is specified this way in the first place,
perhaps a designer can weigh in on that. I do know that ObjC is very
similar, so there may be compatibility implications.

2. We could introduce additional syntax to provide compiler diagnostics
to guard in this case, e.g.

func lessEvil(@noescape foo:evilArg ) { //@noescape currently not
supported for non-closure parameters
     self.strongReference = foo //should generate diagnostic about
escaping a @noescape parameter
}

and then

dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0)) {
[strong self] in
            evil(metadata) //should generate diagnostic that self is
required for functions without @noescape
            lessEvil(metadata) //no diagnostic since parameter is
@noescape
}

I think both of these fixes to the proposal are fairly impractical, but
they would weaken my vote to -0.5.

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

+1 also for the proposal.

It might even be clearer than the actual behavior.

Pierre

···

Le 16 déc. 2015 à 09:05, ilya via swift-evolution <swift-evolution@swift.org> a écrit :

+1 explicit is better than implicit (capture of self)

This should also be promoted by style guides. It's easy for a novice to miss that self.property captures the whole self, the capture list is much more useful in that regard.

On Wed, Dec 16, 2015 at 05:06 Matthew Johnson via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
I believe it has been made clear upthread now, but only the closure is capturing self. Your evil function only stores a copy of the dictionary.

This behavior is identical whether you use [strong self] and metadata or you use self.metadata so I don’t understand why it would be an argument against the proposal. Either way the capture of self by the closure is explicitly represented in the code where it happens. [strong self] actually seems a bit more clear to me.

An example that behaves like you stated could be concocted if we modify your example to pass a bound method rather than a property value, however that seems pretty unlikely to happen unintentionally even if / when we can obtain references to bound property getters / setters.

typealias evilArg = [String:String]
var strongReference: () -> evilArg
func evil(foo: () -> evilArg ) {
    strongReference = foo
}

final class Photo {
    var data = [UInt8](count: 100000000, repeatedValue: 0) //a large amount of data
    func metadata() -> [String: String] { return [:] }

    func save() {
        dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0)) {
            evil(self.metadata)
        }
    }
}

I understand why you’re afraid of anything that might lead to unintentionally storing a strong reference or creating a reference cycle. I don’t understand why this proposal is likely to make that happen. I would even argue it might make it less likely to happen. If developers get in the habit of using the capture list rather than explicitly using “self.” in the body they will be more likely to capture only what they need. In your example the developer may have specified [metadata = self.metadata] rather than using [strong self] if the metadata value at the time of closure capture was sufficient.

Matthew

On Dec 15, 2015, at 7:23 PM, Drew Crawford via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Dec 15, 2015, at 7:15 PM, Greg Parker <gparker@apple.com <mailto:gparker@apple.com>> wrote:

We could make it more difficult for unaware programmers to *write* the `[strong self]` version, at least. When a programmer writes just `metadata` in a closure, the compiler could continue to suggest using `self.metadata` and not suggest using `[strong self]`.

That's not (especially) the danger I'm worried about.

I'm worried about the case where I write `[strong self] in` and then years later I add the `evil(f)` to the bottom of the closure, because it turns out we need more code in there.

I'm also worried about the case where I write nonEvil(f) but at some later time the implementation of nonEvil(f) becomes evil.

I'm also worried about the case where nonEvil(f) is a call into closed-source UIKit and without any visibility to me, UIKit's implementation of nonEvil becomes evil between iOS10b3 and iOS10b4.

These things are "category 5" bugs waiting to happen, and they can't be competently addressed with a UI-level fix in Xcode.

_______________________________________________
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

Thanks. That helps a lot.

- Paul

···

On Jan 23, 2016, at 12:46 PM, David Smith <david_smith@apple.com> wrote:

Generally speaking, memory management schemes are "shippably fast, deterministic, cycle collecting: pick at most 2". ARC picks 1 and 2, tracing garbage collectors pick 1 and 3.

    David

On Jan 23, 2016, at 12:22 PM, Paul Ossenbruggen via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I am very sure this is covered elsewhere, could someone point me to a discussion of why we can’t automate the removal of self cycles for closures. Is it because it essentially means that we need a garbage collector? This seems like one of the biggest stumbling blocks for new developers and even experienced developers of iOS. ARC was brilliant in that it eliminated 95% writing code to deal with memory issues, but for this one. What about a solution that just solved this one problem with closures and not a general solution that solved all memory cycles? Is that feasible? The strong and weak is pretty easy to understand everywhere else except the closure case, I know lots of people who don’t fully understand when you need to use weakSelf and strongSelf etc. Anyway, i am sure this has been discussed in depth just want to understand all the issues. Also, this may not be strictly a swift topic.

On Jan 23, 2016, at 9:38 AM, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jan 23, 2016, at 1:26 AM, Marc Knaup <marc@knaup.koeln <mailto:marc@knaup.koeln>> wrote:

Is the self requirement when using [self] capture still necessary once the limitations outlined by Chris Lattner are solved?
Or does this change still have to go through Swift Evolution?

Once we have [self] in closures, I think it is obvious that the "self.” requirement would be disabled for any closure that uses it.

-Chris

On Fri, Dec 18, 2015 at 1:21 AM, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
FWIW, I’m also +1 on this proposal, but it should just be a capture list of [self], since all captures are strong by default. This is also part of the intended design of capture lists. The only reason we don’t do this already is that there are some implementation limitations (aka, hacks) around name lookup of “self" that need to be unraveled.

-Chris

> On Dec 17, 2015, at 2:20 PM, Rudolf Adamkovic via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>
> +1
>
> I've been writing a lot of experimental UIKit animation code past couple of days and spent most of my time adding and removing "self".
>
> R+
>
> Sent from my iPhone
>
>> On 16 Dec 2015, at 00:02, Greg Parker via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>
>> Swift currently requires that `self` be used explicitly inside closures, to help avoid bugs from unintentional capture. This is annoying when a closure uses `self` a lot. Closures should be allowed to name `[strong self]` in their capture list and thereafter not be required to write `self` everywhere.
>>
>> I wrote code this weekend that looked something like this:
>>
>> data = ...
>> running = true
>> delegate.notifyBegin(data)
>>
>> dispatch_async(queue) {
>> self.processData(self.data)
>> self.running = false
>> self.delegate.notifyEnd(self.data)
>> }
>>
>> Note the asymmetry: the dispatched code needs to use `self` and the non-dispatched code does not. It is clear that the dispatched closure captures `self`, but it's annoying that it needed to be mentioned five different times. The noise gets worse with longer closures. The annoyance gets worse when moving code in and out of dispatches or other closures, with lots of editing required each time.
>>
>> The proposal would allow the same code to be written like this:
>>
>> data = ...
>> running = true
>> delegate.notifyBegin(data)
>>
>> dispatch_async(queue) {
>> [strong self] in
>> processData(data)
>> running = false
>> delegate.notifyEnd(data)
>> }
>>
>> Advantages:
>> * The dispatch'ed code looks like the non-dispatched code.
>> * The capture of `self` is still obvious.
>> * The code's action is clearer without the `self` noise.
>>
>> Disadvantages:
>> * The capture behavior of self's properties is less obvious. For example, neither closure above captured its own copy of `self.data`, but that behavior is not immediately visible in the second closure.
>>
>>
>> What about [weak self] and [unowned self] ? I do not propose to change the `self` requirement for those closures. In the weak case it is critically important to know where `self` is accessed, because it could potentially become nil between any two accesses. Unowned self might be reasonable to change, but for simplicity I won't do so here.
>>
>>
>> --
>> Greg Parker gparker@apple.com <mailto:gparker@apple.com> Runtime Wrangler
>>
>>
>> _______________________________________________
>> 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