[swift-evolution] RFC: Proposed rewrite of Unmanaged<T>

Janosch Hildebrand jnosh at jnosh.com
Tue Dec 29 15:01:49 CST 2015

> On 19 Dec 2015, at 22:09, Dave Abrahams <dabrahams at apple.com> wrote:
>> On Dec 18, 2015, at 6:18 PM, Janosch Hildebrand via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>> ...
> I don't see any point in having "manuallyRelease()" if we already have "release()"; they'd do the same thing if you dropped the return value.

I like the proposed idea of having two separate types for handling unannotated CF APIs and MRC which would also nicely resolve this issue. 

Would a separate type for MRC also fall under this proposal or would that require a separate proposal?

And speaking of a separate type for MRC, how about `ManagedReference` as a name? Seems much better than `Unmanaged`, nicely contrasts with `UnsafeReference` and `ManuallyManagedReference` is a bit of a mouthful...

>> I don't think this use case even needs to be described in the documentation for `UnsafeReference` and it's fine if its use is very much discouraged.
>> Personally I prefer the proposed `manuallyRetain()`/`manuallyRelease()` over plain `retain()`/`release()` as it clearly separates the returning and more generally applicable `release()` from the MRC methods. `retain()` would probably also have to return the object which would interfere with the max safe usage pattern.
> I don't understand your last sentence; care to clarify?

My main reason for preferring `manuallyRetain()`/`manuallyRelease()` over `retain()`/`release()` would be that the former would *not* return the object, thus more cleanly separating them from the current `release()` which returns the object to be used from now on, with the `UnsafeReference` to be discarded at that point.

I just think it might be more confusing to also use `release()` for MRC and also introducing `retain()` would only exacerbate the issue. For symmetry reasons `retain()` would likely also return the object. That would make it very similar to `release()` and `.object` which it really shouldn't be as it shouldn't ever be used for handling object from unannotated CF APIs.

I think having a third method/property with a very similar signature would likely confusion regarding the "Maximally Safe Usage" pattern you described.

But as mentioned above I would actually prefer having two separate types which would also make this a non-issue.

>> As Joe mentioned, `Unmanaged` has a use for manual ref counting beyond immediate transfer from un-annotated APIs. 
>> I have used it for performance reasons myself (~ twice) and while I think it's a pretty small use case there isn't really any alternative.
>> If it would help I can also describe my use-cases in more detail.
> Yes please!

One place I used Unmanaged is in a small project where I experiment with binary heaps in Swift. I've put the project on Github --(https://github.com/Jnosh/SwiftBinaryHeapExperiments) but basically I'm using `Unmanaged` in two places here:

1) Testing the 'overhead' of (A)RC.
Basically comparing the performance of using ARC-managed objects in the heaps vs. using 'unmanaged' objects. In Swift 1.2 the difference was still ~2x but with Swift 2+ it's likely approaching the cost of the retain/release when entering and exiting the collection.

Now this could also be accomplished using `unowned(unsafe)` but `Unmanaged` has some minor advantages:
	a) I can keep the objects alive without keeping them in a separate collection. Not a big issue here since I'm doing that anyway but I also find that `Unmanaged` makes it clearer that & how the objects are (partly) manually managed.
	b) I had previously experimented with using `unowned(unsafe)` for this purpose but found that `Unmanaged` performed better. However, that was in a more complex example and in the Swift 1.2 era. A quick test indicates that in this case and with Swift 2.1 `unowned(unsafe)` and `Unmanaged` perform about equally.

2) A (object only) binary heap that uses `Unmanaged` internally
Not much practical use either in this case since the compiler seems to do quite well by itself but still a somewhat interesting exercise.
`Unmanaged` is pretty much required here to make CoW work by manually retaining the objects.

The other project was a simple 2D sprite engine (think a simplified version of SpriteKit) I experimented with about a year ago.
Textures and Shaders were abstracted as value types privately backed by reference types that managed the underlying OpenGL objects, i.e. destroy the OpenGL texture object on deinit, etc...

I found this to be quite nice to use but ARC overhead during batching & rendering amounted to something like 20-30% of CPU time IIRC. (This was under Swift 1.2 and with WMO). Using `Unmanaged` was one of the things I played around with to get around this and it worked very well.
The `Unmanaged` instances were created when draw commands are submitted to the renderer so they were only used inside the rendering pipeline.
I eventually switched to using the OpenGL names (i.e. UInts) directly inside the renderer since they are already available anyway but that also requires extra logic to ensure the resources are not destroyed prematurely (e.g. retaining the object until the end of the frame or delaying the cleanup of the OpenGL resources until the end of the frame, ...). In many ways it's quite a bit messier than just using `Unmanaged`.

I don't think these are particularly great examples and I could certainly live without 'native' MRC but ultimately I think it's an interesting capability so I'd like to keep it around. Although I'd be in favor of keeping it out of the stdlib but I don't think that's really an option just yet...

It would also be interesting to be able to do the same with indirect enum instances and closures but it's not like I have a particular use case for that ;-)

- Janosch

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151229/91d86c92/attachment.html>

More information about the swift-evolution mailing list