There's still the "release" issue (std::unique_ptr::release versus -[NSObject release]), but "transfer" seems like a good word to me. What about "transferByRetaining" and "transferWithoutRetaining"?
Félix > Le 20 déc. 2015 à 00:01:22, Nevin Brackett-Rozinsky via swift-evolution > <swift-evolution@swift.org> a écrit : > > Floating an idea here—not sure if it’s even in the right ballpark, and I’m > certainly not tied to the specific wording, but what about something along > the lines of: > > .transferByReleasing() > .transferWithoutReleasing() // or perhaps just .transfer() > > Or the slightly-more-verbose: > > .transferObjectByReleasingReference() > .transferObjectWithoutReleasingReference() // or .transferObject() > > Nevin > > > On Sat, Dec 19, 2015 at 11:37 PM, Jacob Bandes-Storch via swift-evolution > <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote: > Hi Dave, > Thanks for sharing the proposal. I finally had a chance to catch up with the > discussion. > > Generally I like the proposal and it would serve my needs well. > > I share others' concern that completely manual retain/release calls should > still be allowed in some way. This doesn't have to be via UnsafeReference, > but I don't think it makes sense to replace Unmanaged with UnsafeReference as > proposed without some solution to this. > > Regarding naming: > > > problems with Unmanaged that we wanted to fix: > > It was poorly-named (the reference is managed by somebody, we just aren't > > representing that management in the type system). > > I don't really agree with this. The management isn't "not represented" — the > Unmanaged type explicitly says, at least to me, "this particular reference to > the object does not manage its lifetime". So I don't think UnsafeReference is > particularly an improvement here, though I'm not against it. > > - The release() name makes sense to me; it behaves like > removeFirst/removeAtIndex. I'd also suggest something like > consumeReference(). And for manual retains, if that's in scope for this API, > you could use addReference(). > > Regarding COpaquePointer: > > - Just to clarify, it looks like the proposed API would produce usage > patterns like: > > someCFunction(context: COpaquePointer(UnsafeReference(retaining: self))) > > func myCallback(context: COpaquePointer) { > let object = UnsafeReference<Foo>(bitPattern: context).object > } > > func myCleanup(context: COpaquePointer) { > UnsafeReference<Foo>(bitPattern: context).release() > } > > - I'm curious why you chose a COpaquePointer initializer, rather than > toOpaque() as the current Unmanaged API provides? On my > UnsafePointer+Unmanaged proposal, you commented > <https://github.com/apple/swift-evolution/pull/44#issuecomment-165902471> "we > can’t give just UnsafePointer<Void> an init taking an UnsafeReference". But > (a) it sounds like this is an eventual goal (I started working on it but it's > a bit over my head currently); (b) using toOpaque() instead solves this > problem: > > func toOpaque() -> UnsafePointer<Void> { > return unsafeBitCast(_storage, UnsafePointer<Void>.self) > } > ... > someCFunction(context: UnsafeReference(retaining: self).toOpaque()) > > My motivation here is mostly that C void* APIs are currently bridged as > UnsafePointer<Void>, so APIs that produce COpaquePointer are an obstacle to > using them. If the trend is away from UnsafePointer and toward better > "Opaque" semantics, that's fine with me; I'd just like the API to be easy to > use in the meantime. > > In the same comment you also said "pointers to Void and incomplete types are > not in any sense “unsafe” (once you restrict the interface as appropriate for > incomplete types), and so maybe we want OpaquePointer<T> for these". It seems > to me, though, that anything which can operate on arbitrary memory addresses > is indeed Unsafe. > > Regarding documentation comments: > > - It might be worth mentioning that init(retaining:) and > init(withoutRetaining:) are most likely to be used before conversion to an > opaque pointer, rather than immediately calling .object or .release() which > wouldn't be a very useful pattern. > > - A weakness I see is that CF/other C APIs won't have comments saying which > "state" the returned UnsafeReference is in. The UnsafeReference doc comments > are very clear about which operations may be used when, but the user is > forced to mentally translate "…responsible for releasing…" into "this > reference is in the *retained* state" — a possible source of confusion, > unless all the CF doc comments can be reworded when they're imported into > Swift to be more explicit. > > - Very minor: your doc comment on "public var object" has a stray/double `. > Similarly, the top-level comment has a stray/double ". > > Jacob Bandes-Storch > > On Sat, Dec 19, 2015 at 7:43 PM, Dave Abrahams via swift-evolution > <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote: > > > On Dec 19, 2015, at 4:22 PM, Brent Royal-Gordon <br...@architechies.com > > <mailto:br...@architechies.com>> wrote: > > > >>> Mainly, because simply saying "release" or "released" is a bit ambiguous > >>> to me.Are you saying it *has been* released, or are you saying it *needs > >>> to be* released? > >> > >> But nobody proposed "released" as a method name. In what way is "release" > >> ambiguous? It's an imperative verb. > > > > I guess you're right that "release" is unambiguous, but as you mentioned, > > it's also strange to release a value and then use it. > > Yes. I think there are no really great choices here (at least not so far) so > the question is whether that strangeness is enough of a problem to outweigh > the points release() has in its favor. What do you think? > > > I think what I'm trying to get at here is that I prefer to think of the > > operations on Unmanaged as "explain to ARC how it should handle this > > object", rather than "do some manual operations so that ARC will do the > > right thing". Maybe the current Unmanaged design has shown the limitations > > of that approach, though. > > Not at all; the Unmanaged design—at least in my best understanding of its > intent—is firmly in the imperative/manual operations camp. I wanted to do > something more declarative, but the "I want to manage the reference that I > claim was passed to me at +1" operation is side-effectful. Are we really > comfortable with hiding that fact? > > >> But you applied "take" to both of them? One of them is idempotent while > >> the other is not. > > > > The preferred way to use Unmanaged is that you immediately convert it to a > > managed reference without ever storing it or using it in any other way. > > That means you should immediately call either the retain-and-return > > operation or the don't-retain-and-return operation. Both of these should > > only ever be called once. You may instead choose to keep the reference > > Unmanaged and manually retain, release, and access it, but best practices > > discourage that. > > As I said in my original post, I'm ambivalent about the importance of > highlighting the distinctions of safety and idempotence between these > methods, but even if they're named similarly I don't see any merit in > starting with "take." One thing I really dislike about is that the receiver, > the UnsafeReference, isn't "taking" anything. The *caller* might be said to > be taking something from the UnsafeReference, but only in the "returned at > +1" case. > > How I see it: along with the UnsafeReference the called CF function either > notionally > a) gives (possibly-shared) ownership of the object directly to the caller, or > b) gives the caller a token that allows him to get (shared) ownership of the > object > > In case a), the caller needs to ask the UnsafeReference to transfer (or > "release") that ownership into a strong reference, and. In case b), the > caller needs to explicitly get (shared) ownership. > > If this description doesn't sound right to you, please try to correct it; > that may help me understand your perspective better. > > > Now, one of the preferred, do-only-once operations *happens* to be safe to > > apply more than once, but I view that as an implementation detail. Both of > > them *happen* to be implemented in the same way as manual operations > > (`manuallyRelease()` and `object`), but I view that as an implementation > > detail, too. > > Hm, well, I don't view `object` as a "manual operation" and there's value in > having a smaller API surface area. I don't think I want a separate > `manuallyRelease` method if there is another method that has the same > semantics. One of the greatest weaknesses of the current Unmanaged is that > its interface is too broad and hard to grasp. > > > Honestly, I might be happier splitting an UnsafeReference type out of > > Unmanaged and putting the manual retain/release stuff into that: > > As noted in my original post, I really don't want to keep the name > "Unmanaged" for anything. If anything, it's "ManuallyManaged." And I am > very wary of API surface area creep here, whether it's in one type or two. > > > // Unmanaged is a high-level type for moving object references in and > > out of ARC's control. > > struct Unmanaged<T: class> { > > func created() -> T > > func gotten() -> T > > > > // Also would have stuff for passing, which I haven't even > > thought about yet > > } > > > > // UnsafeReference is a low-level type for manually managing the > > retain count of an object. > > struct UnsafeReference<T: class> { > > init(_ object: T) > > init(_ unmanaged: Unmanaged<T>) > > > > var object: T > > > > // Some or all of these might return T > > func retain() > > func release() > > func autorelease() > > } > > > > This puts the discouraged manual operations off in their own type where > > they'll be available to those who know about them, but not sitting right > > there on every unaudited call. > > > >>> (I kind of want to suggest that retrieving an object through these calls > >>> should destroy the reference so it can't be used again, but I don't think > >>> that fits with Swift's mutation model without turning > >>> `Unmanaged`/`UnsafeReference` into a reference type and adding lots of > >>> overhead.) > >> > >> Yes, there's no way to reconcile that with the safety offered by the > >> recommended usage patterns, since you can't mutate an rvalue. > > > > I thought so. That's too bad. (I wonder if the compiler can emit warnings > > instead, though.) > > I don't know what you have in mind here. > > > > >>> (One possibility would be to have a single call with an enum parameter, > >>> like `bridge(.Create)` and `bridge(.Get)`. This would let you use the > >>> regular form of the verb.) > >> > >> There's no "bridging" going on here, though. This is simply "turn this > >> unsafe thing into a safe thing in one of two ways" > > > > The "bridge" here comes from the Objective-C bridging casts, but I think > > there it's meant to refer to toll-free bridging, which is not what's > > happening in Swift. > > > > If the type name remains `Unmanaged`, then perhaps `manage(_:)` would be > > better? (I don't like `managing` here because that again implies it's > > side-effect-free and safe to call more than once.) > > Well again, we're not asking the receiver, the UnsafeReference, to manage > anything. And don't forget, we have two operations and need two names, > especially if you want them to feel similar. > > >> So far, my personal assessment of this direction is that it's no better > >> than what I proposed, and has several weaknesses I'd like to avoid. In > >> fact, it seems very similar to and roughly as understandable as the > >> current Unmanaged design. I recognize that this is a highly subjective > >> judgement, so if others disagree with me, I'd really like to hear about > >> it. This is a tough design space and ultimately, what resonates best with > >> the community is likely to be the best choice. > > > > I understand. I'm obviously struggling with this too, as you can see from > > how much I'm changing my design based on your replies, rather than > > defending the design as suggested before. > > > > Ultimately, Unmanaged is an API for handling an abstraction failure. That's > > inherently going to be tricky and subjective. > > Yup. > > -Dave > > > > _______________________________________________ > swift-evolution mailing list > swift-evolution@swift.org <mailto:swift-evolution@swift.org> > https://lists.swift.org/mailman/listinfo/swift-evolution > <https://lists.swift.org/mailman/listinfo/swift-evolution> > > > _______________________________________________ > swift-evolution mailing list > swift-evolution@swift.org <mailto:swift-evolution@swift.org> > https://lists.swift.org/mailman/listinfo/swift-evolution > <https://lists.swift.org/mailman/listinfo/swift-evolution> > > > _______________________________________________ > swift-evolution mailing list > swift-evolution@swift.org <mailto:swift-evolution@swift.org> > https://lists.swift.org/mailman/listinfo/swift-evolution > <https://lists.swift.org/mailman/listinfo/swift-evolution>
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution