@convention(block) blocks should conform to AnyObject

It seems to me that @convention(block) blocks should be considered at compile-time to conform to AnyObject. It's already an object pointer at runtime, and casting to AnyObject preserves the existing pointer (this can be confirmed at the REPL).

The primary use-case for having this be considered to conform to AnyObject is the ability to use Unmanaged to explicitly control its lifetime (extremely useful for passing ownership of a block to a queue to ensure it deallocates on that queue). I could just cast it to AnyObject but then I'd have to do an as! cast back and I don't like that unsafety. My workaround in PMHTTP uses a wrapper private class to hold the block, which is doable but annoying and involves otherwise-unnecessary allocation (though in this case the block in question isn't @convention(block) so this pitch wouldn't actually solve it here, but it would for the work I'm trying to do right now).

There's probably other scenarios where having such a block inherit from AnyObject would be useful as well, but Unmanaged is the only one I can think of off the top of my head.

Note that this would only be possible on Darwin platforms. @convention(block) is not AnyObject-compatible on platforms without ObjC interop.

What does @convention(block) even do on non-ObjC platforms? Is it just ignored there?

It uses the Clang block ABI, which is platform-independent aside from the ObjC id-compatibility bits. It doesn't show up much outside of Darwin, but does appear in the implementations of corelibs Foundation and Dispatch.

2 Likes

Interesting.

If you have any alternative ideas for solving my "pass ownership of a block to a queue/thread such that I don't release on the current thread after" that I'm trying to use Unmanaged for, I'm all ears.

The root problem here is the block capturing a thread-confined object, passing through a background thread, then inadvertently deallocating on that background thread, thus releasing (and potentially deallocating) the thread-confined object on the wrong thread.

Personally I'm ok with this only being supported on Darwin, since that's all I care about, but I realize that we're trying to minimize platform behavioral differences.

Yeah, I don't know that platform divergence has to be a showstopper in this case, since I don't think there'd ever be much use of blocks on other platforms to begin with above the corelibs glue layers.

3 Likes