<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=""><br class=""><div><blockquote type="cite" class=""><div class="">On May 16, 2017, at 5:20 PM, Jordan Rose <<a href="mailto:jordan_rose@apple.com" class="">jordan_rose@apple.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="" applecontenteditable="true"><br class=""><div class=""><blockquote type="cite" class=""><div class="">On May 15, 2017, at 20:29, John McCall <<a href="mailto:rjmccall@apple.com" class="">rjmccall@apple.com</a>> wrote:</div><br class="Apple-interchange-newline"><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=""><blockquote type="cite" class=""><div class=""><br class="Apple-interchange-newline">On May 15, 2017, at 9:00 PM, Jordan Rose <<a href="mailto:jordan_rose@apple.com" class="">jordan_rose@apple.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" applecontenteditable="true" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class="">[Proposal: <font face="-apple-system-body, Helvetica, arial, sans-serif" class=""><span class="" style="background-color: rgb(255, 255, 255);"><a href="https://github.com/apple/swift-evolution/blob/master/proposals/0176-enforce-exclusive-access-to-memory.md" class="">https://github.com/apple/swift-evolution/blob/master/proposals/0176-enforce-exclusive-access-to-memory.md</a></span></font>]</div><div class=""><br class=""></div><div class="">I have severe concerns about these revisions because they make withoutActuallyEscaping harder to reason about.</div><div class=""><br class=""></div><div class="">+ - Programmers using ``withoutActuallyEscaping`` should take</div>+ care not to allow the result to be recursively invoked.<div class=""><br class=""></div><div class="">+[…] if they are certain that their code will<br class="">+not violate the NRR, use ``withoutActuallyEscaping`` to disable<br class="">+the NPCR check.<br class=""><br class=""><div class="">I think this constitutes a violation of the user model for withoutActuallyEscaping, because withoutActuallyEscaping hasn't historically meant withoutBeingReentrant. The proposal "should take care" is a very mild way of saying we're introducing a new rule under which the compiler can silently do something different than what you wrote (with no "unsafe" in sight). Similarly, using withoutActuallyEscaping to mean withoutActuallyViolatingExclusivity seems like it'll come back to haunt us, the kind of thing where people ask on Stack Overflow why the Swift people didn't design something that said what it did.</div></div></div></div></blockquote><div class=""><br class=""></div>You're right that it's a silent change in the semantics of withoutActuallyEscaping. I'm comfortable with that because of the ways in which I expect withoutActuallyEscaping to be used, but I can see why someone wouldn't be.</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=""><blockquote type="cite" class=""><div class=""><div class="" applecontenteditable="true" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><div class="">When I first brought this up on an Apple-internal list, John let me know that we could introduce checking for it. This helps assuage my concerns quite a bit, but I'm not sure how we would do so without modifying the original closure, and if we can modify the original closure I'm not sure we've saved anything over proper dynamic checking.</div></div></div></div></blockquote><div class=""><br class=""></div><div class="">withoutActuallyEscaping does not actually promise to return exactly the original closure (which is not a user-detectable property of the closure value), just something semantically equivalent. In particular, we can wrap it in a thunk that (say) dynamically asserts that the closure is not called re-entrantly.</div><div class=""><br class=""></div><div class="">We may need withoutActuallyEscaping to add a thunk anyway, because I don't know that we actually want to guarantee that the context pointer of a non-escaping closure is retainable; it costs us unnecessary set-up code in the caller.</div></div></div></blockquote><div class=""><br class=""></div><div class="">I thought of this too, but it doesn't handle the case where you use withoutActuallyEscaping <i class="">and</i> use the original closure directly from within the block. Maybe we can forbid that, though—it seems extra-rare. Does it make sense to add that as an extra rule in this proposal?</div></div></div></div></blockquote><div><br class=""></div><div>Well, you'd have to integrate the check with some sort of record-keeping done by the original closures. I'm not entirely sure what that record-keeping would look like off-hand.</div><div><br class=""></div><div>I'm not sure what you're proposing to disallow here. I don't think we should add any extra restrictions in order to avoid problems with unfortunate uses of withoutActuallyEscaping, though.</div><div><br class=""></div><div>John.</div><div><br class=""></div></div><div><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="" applecontenteditable="true"><div class=""><div class=""><br class=""></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=""><div class=""><br class=""></div><blockquote type="cite" class=""><div class=""><div class="" applecontenteditable="true" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><div class="">John, can you clarify for the list<span class="Apple-converted-space"> </span><i class="">how</i> we might check for this? Like withoutActuallyEscaping, it doesn't have to be something we implement right away as long as we have the ability to do so without changing the ABI.</div><div class=""><br class=""></div><div class="">Thanks,</div><div class="">Jordan</div><div class=""><br class=""></div><div class="">P.S. Devin and I had previously discussed an additional example that does not seem to be forbidden by these rules. Is that correct and will this program continue to print "2 2"?</div><div class=""><br class=""></div></div><blockquote class="" style="margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div class=""><div class="">func invoke(_ callback: /*nonescaping*/ () -> Void) {</div></div><div class=""><div class=""> callback()</div></div><div class=""><div class="">}</div></div><div class=""><div class="">class Foo {</div></div><div class=""><div class=""> var op: () -> Void = {}</div></div><div class=""><div class=""> var prop = 0</div></div><div class=""><div class=""> func test() {</div></div><div class=""><div class=""> var x = 0</div></div><div class=""><div class=""> self.op = { x = 1; self.prop = 1 }</div></div><div class=""><div class=""> invoke { self.op(); x += 1; self.prop += 1 }</div></div><div class=""><div class=""> print(x, self.prop)</div></div><div class=""><div class=""> }</div></div><div class=""><div class="">}</div></div><div class=""><div class="">Foo().test()</div></div></blockquote></div></div></blockquote><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="">Correct. The closure passed to 'invoke' does recurse into a closure that captures the same variable, but that closure is not non-escaping, so the NRR is not violated.</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="">On a design-intent level, recursing into an escaping closure is fine because any variable captured in an escaping closure is escaping, and therefore the accesses to it are generally not statically analyzable and must use dynamic enforcement.</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="">(I did just now notice the phrasing of the NRR in the proposal isn't clear about the restriction only forbidding *indirect* recursion, but your example doesn't violate the stronger rule either. This can be fixed later because it's just a weakening.)</div></div></blockquote><br class=""></div><div class="">Thanks for the clarification!</div><div class="">Jordan</div><br class=""></div></div></blockquote></div><br class=""></body></html>