Thanks for the very interesting design discussion so far. It's exactly what I was wanting to see :)
I'm going to incorporate some of this in the next draft of the proposal. I'm also going to add that there should be an asUnsafeEscapingClosure(_:) helper that will convert a default/noescape closure to an escaping one. For the initial implementation it could use unsafeBitCast(_:to:) to perhaps be changed later. On Thu, Jun 9, 2016 at 8:29 PM, John McCall <[email protected]> wrote: > On Jun 9, 2016, at 4:15 PM, Jordan Rose <[email protected]> wrote: > > On Jun 9, 2016, at 16:10, John McCall <[email protected]> wrote: > > On Jun 9, 2016, at 3:43 PM, Jordan Rose via swift-evolution < > [email protected]> wrote: > > I'm against this for library evolution reasons: if someone releases a > version of their library that has a non-escaping closure and later > discovers it needs to be escaping, they can't change it. > > IIRC the counterpoint to this is that people were probably implicitly > relying on it being non-escaping already, and that there aren't many cases > where you'd want to do this anyway. > > > Right. APIs are already semantically constrained in how they're allowed > to use their closure arguments. Closure arguments inject arbitrary code, > with arbitrary data access, into the callee; as a rule, the caller must > know how the callee intends to use the closure, or its semantics will be > grossly violated. You can't re-implement an existing API that always > synchronously sub-invokes a closure to instead call the closure > asynchronously or concurrently because it is completely reasonable for the > caller to pass a closure that relies on being called synchronously or from > at most one thread at once and/or within a fixed range of time. For > example, the closure may modify a captured local variable, or it may it use > a network connection that will be closed after the API returns. APIs that > want to do this sort of thing have to reserve the right to do that (and > even then, they may have binary compatibility limitations), in which case > it is totally reasonable to expect them to express that in the type. > > > I don't buy this. If someone publishes an API that executes something on > the current thread today and on a background queue tomorrow, that's totally > fine if they never promised it would execute on a particular thread. If a > client accidentally assumes an implementation detail is part of the > interface, that's their fault, and always has been…though the library > author might decide to continue supporting their use in the future in the > interest of not making waves. > > > Synchronous-but-off-thread is kind of a special case because it's only > observable in very special ways, e.g. thread-local storage and the current > thread ID. Concurrent (e.g. calling an enumeration callback on multiple > threads simultaneously) and asynchronous (even if it comes back to the > current queue) are absolutely something you have to know about as a > caller. It is deeply unreasonable for an API to suddenly start invoking a > closure asynchronously when it hasn't documented that it might do that > (perhaps implicitly by obviously following some well-known pattern, e.g. > calling the closure a completion handler); that would be a huge semantic > and binary-compatibility problem. > > Another line of argument: flipping the default is a huge boon to static > analysis because (1) closure execution becomes ordered by default and (2) > an escaping closure becomes a much more meaningful hint. For example, > consider a use-after-free static analysis that sees this code: > > func foo(ptr: UnsafeMutablePointer<Int>) { > bar { ptr[5] = 0 } > ptr.dealloc() > } > > This analysis is currently blocked by this abstraction unless it knows > something specific about 'bar'. If 'bar' marks its argument @noescape, > then the analysis knows that this is safe; but if not, the analysis is > unlikely to be willing to warn because it's quite likely that 'bar' is just > missing an annotation and does not actually execute its closure > asynchronously. However, if the polarity is flipped, the analysis wins on > both ends: it can prove correctness in many more cases by default, and the > cases where the closure actually escapes become much more suspicious, > probably enough to warn by default. > > John. > -- Trent Nadeau
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
