> On May 15, 2017, at 20:29, John McCall <[email protected]> wrote:
>
>>
>> On May 15, 2017, at 9:00 PM, Jordan Rose <[email protected]
>> <mailto:[email protected]>> wrote:
>>
>> [Proposal:
>> https://github.com/apple/swift-evolution/blob/master/proposals/0176-enforce-exclusive-access-to-memory.md
>>
>> <https://github.com/apple/swift-evolution/blob/master/proposals/0176-enforce-exclusive-access-to-memory.md>]
>>
>> I have severe concerns about these revisions because they make
>> withoutActuallyEscaping harder to reason about.
>>
>> + - Programmers using ``withoutActuallyEscaping`` should take
>> + care not to allow the result to be recursively invoked.
>>
>> +[…] if they are certain that their code will
>> +not violate the NRR, use ``withoutActuallyEscaping`` to disable
>> +the NPCR check.
>>
>> 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.
>
> 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.
>
>> 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.
>
> 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.
>
> 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.
I thought of this too, but it doesn't handle the case where you use
withoutActuallyEscaping and 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?
>
>> John, can you clarify for the list how 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.
>>
>> Thanks,
>> Jordan
>>
>> 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"?
>>
>> func invoke(_ callback: /*nonescaping*/ () -> Void) {
>> callback()
>> }
>> class Foo {
>> var op: () -> Void = {}
>> var prop = 0
>> func test() {
>> var x = 0
>> self.op = { x = 1; self.prop = 1 }
>> invoke { self.op(); x += 1; self.prop += 1 }
>> print(x, self.prop)
>> }
>> }
>> Foo().test()
>
> 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.
>
> 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.
>
> (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.)
Thanks for the clarification!
Jordan
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution