> On 19 Dec 2015, at 22:09, Dave Abrahams <[email protected]> wrote:
> 
> 
>> On Dec 18, 2015, at 6:18 PM, Janosch Hildebrand via swift-evolution 
>> <[email protected] <mailto:[email protected]>> 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

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to