[swift-evolution] Closure identity (was Re: Compiler directive for current closure reference)

Taras Zakharko taras.zakharko at uzh.ch
Tue Feb 23 07:03:33 CST 2016


Oh, true, I have completely forgot about this litte detail. The truth is, I haven’t tried any pattern like this in Swift yet — it just occurred to my mind because I do use it quite often in a tool I work on now (Python). 

I would also be curious to the reason why closures can’t be compared. I can imagine a bunch of optimisations which make it impossible (e.g. inlining  closure body into another function), but I think this can be solved with some effort. Ideally, I’d like to see something like a Callable/Closure protocol that all closures (including functions and bound methods) adhere to, and which also allows identity comparison. This also opens up a formalism for argument and return type introspection as well as a way to reintroduce the tuple splat operation, e.g. by using an explicit .call() method of the Callable. Of course, details of such a proposal need to be fleshed up. Can someone do that? :)

— Taras

> On 23 Feb 2016, at 05:00, Brent Royal-Gordon <brent at architechies.com> wrote:
> 
>> Closures don't have identity (i.e. you can't use === on them). ObjC blocks do, so if you really need it you can pass things around as @convention(objc_block), but closures don't. So I think you'd have to start there if you want to do anything like this.
> 
> Actually, I've wondered about this for a while.
> 
> Closures are pretty weird in that they're a reference type, but they don't have a stable identity. I asked about this once before Swift was open sourced (I think on Twitter), and I believe I was told that it was due to certain optimizations. What are these optimizations, and can we give closures stable identities despite them?
> 
> In a few minutes of research, my guess is that it has to do with thick vs. thin closures: thick closures carry a context object, while thin ones don't. <https://github.com/apple/swift/blob/master/docs/CallingConvention.rst#closures> Is that the issue here? If so…
> 
> - Leaving aside thin closures for the moment, is a thick closure's context object unique enough to be used as its identity? Is function pointer + context unique enough, or does the function pointer change too?
> 
> - Now, for thin closures, obviously we don't want to allocate an entire unnecessary object to carry an empty context around. But what would the costs be if, instead of omitting the context pointer, we replaced it with a unique integer (presumably with the low bit set to avoid colliding with valid context pointers)? Perhaps keep a thread-local counter and combine it with the thread ID so we don't need any locking?
> 
> (As for motivation: besides just being kind of a weird asymmetry, there are certain classes of APIs which are made more convoluted by the lack of closure identity. Basically any API where you can register and unregister multiple handlers with a single object is affected: the "add" operation has to return some kind of token to be used for the "remove" operation, which may now have a different lifetime from the registration itself. It seems simpler to add and remove the closure itself, but the lack of identity prevents that.)
> 
> -- 
> Brent Royal-Gordon
> Architechies
> 



More information about the swift-evolution mailing list