Jordan, Thank you very much for your response.
Your explanation of what the optimizer is free to do in the face of @inline(never) was enlightening. It's clear that, as Ole was suggesting, I need to make extendLifetime call through to the standard library's withExtendedLifetime to prevent the optimizer from peeking: func extendLifetime<T : AnyObject>(_ t: T) { withExtendedLifetime(handle) {} } And thank you (very much) for calling out that race. I went ahead with the change that you suggested, making AsyncHandle's Handle an IUO var which gets nil'd prior to the call to async. AsyncHandle now looks like class AsyncHandle { var handle: Handle! deinit { let handle = self.handle self.handle = nil q.async { extendLifetime(handle) } } } Thanks again, Nate Chandler On Mon, Feb 27, 2017 at 3:01 PM Jordan Rose <jordan_r...@apple.com> wrote: > > On Feb 27, 2017, at 10:53, Ole Begemann via swift-users < > swift-users@swift.org> wrote: > > On 27/02/2017 19:34, Nate Chandler via swift-users wrote: > > Hi Ole, > > A quick follow-up--are you suggesting calling withExtendedLifetime > inside the closure passed to async, as below? > > class AsyncHandle { > > let handle: Handle > > deinit { > let handle: Handle = self.handle > q.async { > withExtendedLifetime(handle) {} > } > } > } > > > Yes, that's what I'm suggesting. Sorry I didn't make that clear before. > Since you mentioned that you couldn't use the stdlib's _fixLifetime > function, I just wanted to point out that there is a public function in the > stdlib for this purpose. > > If so, it seems that that may be a final answer to (3). It does raise > an additional question, however: > > (6) Would we expect calling withExtendedLifetime to have different > behavior from calling an @inline(never) function from a closure enqueued > async from deinit? > > > Yeah, I don't know the answer, sorry. > > > I'm not an optimizer person, but expecting '@inline(never)' to mean > anything other than "don't inline this" is probably set for failure. The > optimizer is still allowed to look at the body of the function. > withExtendedLifetime is implemented more carefully to prevent eliding the > capture. > > That said, if you're *not* on when the outer deinit gets called 'q', you > still have a raceāit's possible that 'q' will execute the block you give it > before the deinitializer exits! I don't think there's a good way to avoid > this other than to make 'handle' optional (or ImplicitlyUnwrappedOptional) > and explicitly set it to nil before enqueuing the "deallocation block". > > Jordan > >
_______________________________________________ swift-users mailing list swift-users@swift.org https://lists.swift.org/mailman/listinfo/swift-users