<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div dir="auto" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Feb 23, 2017, at 4:28 AM, Matthew Johnson <<a href="mailto:matthew@anandabits.com" class="">matthew@anandabits.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><blockquote type="cite" class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;"><div class=""><br class="Apple-interchange-newline">On Feb 22, 2017, at 7:13 PM, Anton Mironov <<a href="mailto:antonvmironov@gmail.com" class="">antonvmironov@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><blockquote type="cite" class=""><div class=""><br class="Apple-interchange-newline">On Feb 23, 2017, at 02:19, Matthew Johnson <<a href="mailto:matthew@anandabits.com" class="">matthew@anandabits.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><blockquote type="cite" class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><div class=""><br class="Apple-interchange-newline">On Feb 22, 2017, at 6:06 PM, Anton Mironov <<a href="mailto:antonvmironov@gmail.com" class="">antonvmironov@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Feb 23, 2017, at 01:18, Matthew Johnson <<a href="mailto:matthew@anandabits.com" class="">matthew@anandabits.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><blockquote type="cite" class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><div class=""><br class="Apple-interchange-newline">On Feb 22, 2017, at 5:06 PM, Anton Mironov <<a href="mailto:antonvmironov@gmail.com" class="">antonvmironov@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class="">-1</div><div class="">I support improvements in this area but I do not think that adding guarded closures will fix the case.</div><div class="">It raises multiple concerns:</div><div class="">- prepending ? to the closure declaration is as forgettable as `[weak self]`</div></div></div></blockquote><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;">No, this is why I included the `@guarded` parameter annotation. This allows an API to require its callers to use a guarded closure. Strong references would have to be explicit in the capture list.</div><br class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><blockquote type="cite" class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class="">- reactive programming often assumes chaining of operations. How guarded closures affect next operations in the chain?</div></div></div></blockquote><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;">Can you provide a concrete example of real world code you wrote manually? I will convert it to use guarded closures to show how it is affected.</div></div></blockquote><div class=""><br class=""></div><div class="">You can use the second piece of code I’ve provided before.</div></div></div></div></blockquote><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;">How do `map` and `onUpdate` store the reference to the context? Is it weak? If so, what happens when the context is released? After you answer that I will be able to show how it would look under this proposal.</div></div></blockquote><div class=""><br class=""></div><div class="">Yes, they store a weak reference to the context.</div><div class=""><br class=""></div><div class="">This code implies using primitive that has multiple update events (button actions in this case) followed by a single completion event (can only be an error of context deallocation in this case). I call it `Channel` (because name `Stream` is already taken by `Foundation.Stream` aka `NSStream`).</div><div class=""><br class=""></div><div class="">A release of context will lead to a release of closure and all operations it depends on.</div><div class=""><br class=""></div><div class="">`Channel.map`’s context does not exist anymore so closure will be released and `Channel` returned from `map` will be immediately completed with failure.</div><div class="">This will also lead to a release of `Channel` returned by `Channel.debounce()`. `Channel.debounce()` will lead to release of `Channel` returned by `actions(forEvents: [.touchUpInside])`. </div><div class=""><br class=""></div><div class=""><div class="">`Channel.onUpdate`’s context does not exist anymore so closure will be released.</div><div class=""><div class="">This will also lead to a release of `Channel` returned by `Channel.distinct()`.</div><div class=""><br class=""></div><div class="">It might look complex but it is based on a simple idea: release all retained resources if your context is gone.</div></div></div></div></div></blockquote><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">I’m very familiar with patterns like this but didn’t want to make any assumptions about how your code works. How does this code currently detect that the context has been released? Does it wait until an event is pushed through the channel and see that the context is now nil?</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div></div></blockquote><div><br class=""></div>No, it does not wait. It releases all retained resources (closure and channels it depends on) when context drains it’s `disposableBag`.<div><br class=""></div><blockquote type="cite" class=""><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">If this system was using guarded closures the `map` and `onUpdate` methods would specify their function argument `@guarded` which would automatically make all captures guarded. You are not limited to a single context object, but if that is the need of your code you of course can capture a single object.</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div></div></blockquote><div>I did not think of multiple contexts before. Maybe I should. I thought that two (or more) context you want to interact with are either:</div><div>- have a simple relation (child-parent or a regular ownership) so there is no need for the weak reference for the second context</div><div>- are operating on unrelated `DispatchQueue`s so mutation of an internal state of both contexts on the same queue may not exist</div><br class=""><blockquote type="cite" class=""><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">The calling code would look like this:</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">self.button.actions(forEvents: [.touchUpInside])<br class=""> .debounce(interval: 3.0)<br class=""> .map ?{<br class=""> return self.searchField.text<br class=""> }<br class=""> .distinct()<br class=""> .onUpdate ?{ (searchQuery) in<br class=""> self.performSearch(query: searchQuery)<br class=""> }</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">In the implementation of the library where you used to store a weak reference to the context and a strong reference to the closure you would just store a strong reference to the guarded closure. The guarded closure itself manages the weak / strong dance. Where you used to check the weak reference to the context for nil to see if it is alive or not you would check the `isAlive` property on the closure reference to determine if the closure is still alive or not. When it is no longer alive you tear down exactly the same as you do today when you detect that the context reference is nil.</div></div></blockquote><div><br class=""></div><div>That is a point. Next check `isAlive` will be performed right before the next call of the closure. This call could be performed in a minute or in an hour or even never performed. Guarded closure will capture variables until then.</div><br class=""><blockquote type="cite" class=""><div class=""><br class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><blockquote type="cite" class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;"><div class=""><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><div class=""><div class=""><div class=""><br class=""></div></div></div><blockquote type="cite" class=""><div class=""><blockquote type="cite" class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><br class=""><blockquote type="cite" class=""><div class=""><br class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><blockquote type="cite" class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class="">- the closure must exist until either the control deallocates (source of actions) or self deallocates (destination of actions). Guarded closure will not provide an expected behavior</div></div></div></blockquote><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;">Yes they will. The guarded closure lives until the control releases it. But it becomes a no-op if any of the references captured with a guard are released before that happens. This is much like the behavior of the target / action pattern but generalized to support closures.</div></div></blockquote><div class=""><br class=""></div><div class="">I doubt that turning closure into no-op is a simple thing to do. It will require having a registry of closures that depend on an instance. A runtime will have to go through the registry and turn closures into no-op. Or there is an another solution that I do not see.</div></div></div></div></blockquote><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;">What I mean when I say no-op is that the code the user places in the closure would be prefixed by a `guard` clause with an early return. The no-op is when the guard clause is triggered, just as if you had written it manually.</div></div></blockquote><div class=""><br class=""></div>I think that this is an important part. Using no-op (or avoiding execution of closure as I understand it) leads to another unwanted retain of variables captured by the closure.</div></div></blockquote><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">There is no additional retain of the variables over a solution that captures the variables independently of the closure and passes them as arguments if they’re alive when called (like the context in your example). Where do you think you see an extra retain of the variables?</div></div></blockquote><div><br class=""></div>I meant that keeping the closure alive when a context is dead is an extra retain of a captured variables.</div><div><br class=""></div><div>Look, I’m not saying that extra care about retain cycles is bad. I’m just saying that making an implicit weak reference does not solve the whole problem. I think that adding guarded closures is not a step towards a complete solution.</div><div><br class=""></div><div><blockquote type="cite" class=""><div class=""><br class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><blockquote type="cite" class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;"><div class=""><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""><blockquote type="cite" class=""><div class=""><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;">I imagine the compiler might also place an additional check inside the `else` of the `guard` which would release any context it was still hanging on to as it would know that the context was no longer needed. Imagine this as if the compiler synthesized code had access to an optional strong reference to the context and set it to nil in the else clause. It would also be possible for this closure to expose an `isAlive: Bool` property that would check whether or not the context was still around. This is a bit of hand waving - I’m sure the real implementation would be more sophisticated. But I think that conveys the basic idea.</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;">Here is some pseudocode:</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;">let foo: Foo = Foo()</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;">let bar: Bar = Bar()</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;">// hand out references to the owner that controls the lifetime of foo and bar</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;">?{ </div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><div class=""> // compiler synthesized code</div><div class=""> // this is a property on the closure object itself, not visible within the scope of the user code in the closure</div><div class=""> // it is used by libraries to detect when they can safely discard their reference to the closure because it has become a no-op</div><div class=""> // context is a super secret compiler reference to the context of the closure</div><div class=""> var isActive: Bool { return context != nil }</div><div class=""><br class=""></div></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"> // compiler synthesized code that prefixes the user code</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"> guard let foo = foo, let bar = bar else {</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"> context = nil</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"> return</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"> }</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"> // end compiler synthesized code</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"> </div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"> // begin user code</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"> // do something with foo and bar</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;">}</div><br class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><blockquote type="cite" class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><br class=""><blockquote type="cite" class=""><div class=""><br class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><blockquote type="cite" class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class="">- managing lifecycle of nested guarded closures could be complex to understand and implement into the language</div></div></div></blockquote><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;">I’m glad you brought this up. I’ll give it some thought. If there does turn out to be complexity involved I wouldn’t have a problem prohibiting that.</div><br class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><blockquote type="cite" class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class="">- why would you consider using @escaping instead of @guarded?</div></div></div></blockquote><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;">Because sometimes the right default for a function taking an escaping closure is a strong reference. I wouldn't want `DispatchQueue.async` to take a guarded closure. That API doesn’t contain any semantic content around *why* you dispatched async. It’s not a callback, but instead a way of moving work around.</div><br class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><blockquote type="cite" class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><br class=""></div><div class="">I personally prefer doing something like this:</div><div class=""><br class=""></div><div class="">```swift</div><div class="">self.button.onAction(forEvents: [.touchUpInside], context: self) { (self, sender, event) in</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>self.performSearch(query: self.searchField.text)</div><div class="">}</div><div class="">```</div><div class=""><br class=""></div><div class="">or</div><div class=""><br class=""></div><div class="">```swift</div><div class="">self.button.actions(forEvents: [.touchUpInside])</div><div class=""> .debounce(interval: 3.0)</div><div class=""> .map(context: self) { (self, _) in</div><div class=""> return self.searchField.text</div><div class=""> }</div><div class=""> .distinct()</div><div class=""> .onUpdate(context: self) { (self, searchQuery) in</div><div class=""> self.performSearch(query: searchQuery)</div><div class=""> }</div><div class="">```</div><div class=""><br class=""></div><div class="">This code neither requires an addition of language features nor contains retain cycles. All closures will be released as soon as source or destination deallocates.</div></div></div></blockquote><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;">This isn’t too bad but it does require manually threading the context. This is more work for both the library and the client than necessary. It also does not help users avoid an accidental strong reference in the closure. It nudges them not to by offering to thread the context but it doesn’t do anything to prevent it. You can still create a strong reference (event to self) without specifying it in the capture list.</div></div></blockquote><div class=""><br class=""></div><div class="">You are correct. This will code will not help to avoid accidental strong reference. But it gives an opportunity to do things without explicit weak references just as guarded closures do. It also adds an ability to avoid an execution of pure (or just not bound to context) operations you depends on. Deallocation of context will lead to cancellation of full chain of operations and unsubscription from button event.</div><div class=""><br class=""></div><blockquote type="cite" class=""><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;">I think there is a place for a language solution here.</div></blockquote><div class=""><br class=""></div><div class="">The only language solution I expect is a static analyzer warning about retain cycle (like in ObjC).</div><div class=""><br class=""></div><div class="">I’m starting to think that my solution is similar to yours. I’ve done these things with a library rather than with language support. I will definitely take advantage of guarded self in closures as soon as the proposal will be accepted. But I would prefer and suggest using my solution for now.</div><div class=""><br class=""></div><blockquote type="cite" class=""><div class=""><br class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><blockquote type="cite" class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><br class=""></div><div class=""><blockquote type="cite" class=""><div class="">On Feb 22, 2017, at 22:57, Matthew Johnson via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;">Hi David,<div class=""><br class=""></div><div class="">I just shared a draft proposal to introduce guarded closures last week: <a href="https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170213/032478.html" class="">https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170213/032478.html</a>. I think you would find it very interesting.</div><div class=""><br class=""></div><div class="">I considered including a new capture list specifier `guard` in this proposal but decided against it. Guarded behavior requires prefixing the contents of the closure with a guard clause that returns immediately if the guard is tripped. This is a property of the closure as a whole, not of an individual capture. For that reason, I decided that allowing a `guard` specifier for an individual capture would be inappropriate. </div><div class=""><br class=""></div><div class="">Instead, a guarded closure has a guarded by default capture behavior which can be overridden with `weak`, `unowned` or `strong` in the capture list. The thread on this proposal was relatively brief. I plan to open a PR soon after making a few minor modifications.</div><div class=""><br class=""></div><div class="">Matthew</div><div class=""><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Feb 22, 2017, at 2:48 PM, David Hedbor via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class=""><span class="" style="font-size: 12.8px;">Hello,</span><br class="" style="font-size: 12.8px;"><br class="" style="font-size: 12.8px;"><span class="" style="font-size: 12.8px;">(apologies if this got sent twice - gmail and Apple mail seems to confused as to what account the first mail was sent from)</span><br class="" style="font-size: 12.8px;"><br class="" style="font-size: 12.8px;"><span class="" style="font-size: 12.8px;">I’m new to this mailing list, but have read some archived messages, and felt that this would be a reasonable subject to discuss. It’s somewhat related to the recent posts about @selfsafae/@guarded but distinctly different regardless.</span><br class="" style="font-size: 12.8px;"><br class="" style="font-size: 12.8px;"><br class="" style="font-size: 12.8px;"><span class="" style="font-size: 12.8px;">Problem:</span><br class="" style="font-size: 12.8px;"><br class="" style="font-size: 12.8px;"><span class="" style="font-size: 12.8px;">It’s often desirable not to capture self in closures, but the syntax for doing so adds significant boilerplate code for [weak self] or us unsafe when used with [unowned self]. Typically you’d do something like this:</span><br class="" style="font-size: 12.8px;"><br class="" style="font-size: 12.8px;"><span class="" style="font-size: 12.8px;"> { [weak self] in self?.execute() }</span><br class="" style="font-size: 12.8px;"><br class="" style="font-size: 12.8px;"><span class="" style="font-size: 12.8px;">This is simple enough but often doesn’t work:</span><br class="" style="font-size: 12.8px;"><br class="" style="font-size: 12.8px;"><span class="" style="font-size: 12.8px;">{ [weak self] in self?.boolean = self?.calculateBoolean() ]</span><br class="" style="font-size: 12.8px;"><br class="" style="font-size: 12.8px;"><span class="" style="font-size: 12.8px;">This fails because boolean is not an optional. This in turn leads to code like this:</span><br class="" style="font-size: 12.8px;"><br class="" style="font-size: 12.8px;"><span class="" style="font-size: 12.8px;">{ [weak self] in</span><br class="" style="font-size: 12.8px;"><span class="" style="font-size: 12.8px;"> guard let strongSelf = self else { return }</span><br class="" style="font-size: 12.8px;"><span class="" style="font-size: 12.8px;"> strongSelf.boolean = self.calculateBoolean() }</span><br class="" style="font-size: 12.8px;"><br class="" style="font-size: 12.8px;"><span class="" style="font-size: 12.8px;">And this is the boilerplate code. My suggestion is to add a syntax that works the same as the third syntax, yet doesn’t require the boilerplate code.</span><br class="" style="font-size: 12.8px;"><br class="" style="font-size: 12.8px;"><br class="" style="font-size: 12.8px;"><span class="" style="font-size: 12.8px;">Solution:</span><br class="" style="font-size: 12.8px;"><br class="" style="font-size: 12.8px;"><span class="" style="font-size: 12.8px;">Instead of using unowned or weak, let’s use guard/guarded syntax:</span><br class="" style="font-size: 12.8px;"><br class="" style="font-size: 12.8px;"><br class="" style="font-size: 12.8px;"><span class="" style="font-size: 12.8px;">{ [guard self] in</span><br class="" style="font-size: 12.8px;"><span class="" style="font-size: 12.8px;"> self.isExecuted = self.</span><span class="" style="font-size: 12.8px;">onlyIfWeakSelfWasCaptured<wbr class="">()</span><br class="" style="font-size: 12.8px;"><span class="" style="font-size: 12.8px;">}</span><br class="" style="font-size: 12.8px;"><br class="" style="font-size: 12.8px;"><span class="" style="font-size: 12.8px;">In essence, guarded self is equivalent to a weak self, that’s captured when the closure is executed. If it was already released at that point, the closure is simply not executed. It’s equivalent to:</span><br class="" style="font-size: 12.8px;"><br class="" style="font-size: 12.8px;"><span class="" style="font-size: 12.8px;">{ [weak self] in</span><br class="" style="font-size: 12.8px;"><span class="" style="font-size: 12.8px;"> guard let strongSelf = self else { return }</span><br class="" style="font-size: 12.8px;"><span class="" style="font-size: 12.8px;"> strongSelf.isExecuted = strongSelf.</span><span class="" style="font-size: 12.8px;">onlyIfWeakSelfWasCa<wbr class="">ptured()</span><br class="" style="font-size: 12.8px;"><span class="" style="font-size: 12.8px;">}</span><br class="" style="font-size: 12.8px;"><br class="" style="font-size: 12.8px;"><span class="" style="font-size: 12.8px;">Except with a lot less boilerplate code, while not losing any clarify in what it does.</span><br class="" style="font-size: 12.8px;"><br class="" style="font-size: 12.8px;"><span class="" style="font-size: 12.8px;">Impact / compatibility:</span><br class="" style="font-size: 12.8px;"><br class="" style="font-size: 12.8px;"><span class="" style="font-size: 12.8px;">This is simply additive syntax, and wouldn’t affect any existing code.</span><br class=""></div>_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class=""></div></blockquote></div><br class=""></div></div>_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a></div></blockquote></div></div></div></blockquote></div></blockquote></div></div></div></blockquote></div></blockquote></div></div></blockquote></div></blockquote></div><br class=""></div></body></html>