I really love this idea.  My mental model of it is that it is exactly like 
‘defer’, except it works on the lifetime of the object instance instead of a 
function/method.  Same thing, different scope.

I like how the creation and destruction are right next to one another.  It also 
solves a lot of potential issues with partial initialization, I believe.

I might spell it ‘deferToDeinit’ or 'deferUntilDeinit'

The only issue I see is accidentally capturing self strongly.  Is there a way 
to mark a closure as implicitly unowned self so the end programmer doesn’t have 
to worry about it?

Thanks,
Jon
> Twitter tl;dr: 
> > Brent: So each instance must remember which init was used for it and then 
> > run the matching deinit code at deinit time?
> > Me: In my version, the constructive act and destructive act are always 
> > paired, even redundantly, using a stack if needed
> > Graham: so all your deferredDeinit blocks would run, no matter which init 
> > was invoked?
> > Brent: Closure stack in the worst case. Might be able to optimize to 
> > something cheaper if no captures.  Degenerate case: `for i in 0..<10 { 
> > deinit { print(i) } 
> 
> So continuing on from Twitter, assuming the compiler cannot optimize in the 
> case of multiple inits, and init-redirections, how about allowing traditional 
> deinit as well, and introduce compile-time optimization into traditional 
> de-init if the compiler finds only one initialization path per class? We can 
> also warn anyone using my version in a complicated degenerate way that it can 
> be costly through education, manual, etc. It would also help if (especially 
> in Cocoa), you could legally use shared initialization setup closures.
> 
> If I create an observer, I want to be able to handle its end-of-life at that 
> point. If I allocate memory, ditto. Etc etc. Surely Swift should be able to 
> support doing this.
> 
> -- E
> 
> > On Jun 8, 2016, at 3:43 PM, Erica Sadun via swift-evolution 
> > <swift-evolution at swift.org 
> > <https://lists.swift.org/mailman/listinfo/swift-evolution>> wrote:
> > 
> > I really like this idea. Spatially moving cleanup next to unsafe operations 
> > is good practice.
> > 
> > In normal code, I want my cleanup to follow as closely as possible to my 
> > unsafe act:
> > 
> > let buffer: UnsafeMutablePointer<CChar> = 
> > UnsafeMutablePointer(allocatingCapacity: chunkSize)
> >     defer { buffer.deallocateCapacity(chunkSize) }
> > 
> > (Sorry for the horrible example, but it's the best I could grep up with on 
> > a moment's notice)
> > 
> > I like your idea but what I want to see is not the deinit child closure in 
> > init you propose but a new keyword that means defer-on-deinit-cleanup
> > 
> > self.ptr = UnsafeMutablePointer<T>(allocatingCapacity: count)
> >     deferringDeInit { self.ptr.deallocateCapacity(count) }
> > 
> > Or something.
> > 
> > -- E
> > p.s. Normally I put them on the same line with a semicolon but dang these 
> > things can be long
> > 
> >> On Jun 8, 2016, at 10:54 AM, Graham Perks via swift-evolution 
> >> <swift-evolution at swift.org 
> >> <https://lists.swift.org/mailman/listinfo/swift-evolution> 
> >> <mailto:swift-evolution at swift.org 
> >> <https://lists.swift.org/mailman/listinfo/swift-evolution>>> wrote:
> >> 
> >> Teach init a 'defer'-like ability to deinit
> >> 
> >> 'defer' is a great way to ensure some clean up code is run; it's 
> >> declaritive locality to the resource acquisition is a boon to clarity.
> >> 
> >> Swift offers no support for resources acquired during 'init'.
> >> 
> >> For an example, from 
> >> https://www.mikeash.com/pyblog/friday-qa-2015-04-17-lets-build-swiftarray.html
> >>  
> >> <https://www.mikeash.com/pyblog/friday-qa-2015-04-17-lets-build-swiftarray.html>
> >>  
> >> <https://www.mikeash.com/pyblog/friday-qa-2015-04-17-lets-build-swiftarray.html
> >>  
> >> <https://www.mikeash.com/pyblog/friday-qa-2015-04-17-lets-build-swiftarray.html>>
> >> 
> >> init(count: Int = 0, ptr: UnsafeMutablePointer<T> = nil) {
> >>     self.count = count
> >>     self.space = count
> >> 
> >>     self.ptr = UnsafeMutablePointer<T>.alloc(count)
> >>     self.ptr.initializeFrom(ptr, count: count)
> >> }
> >> 
> >> deinit {
> >>     ptr.destroy(...)
> >>     ptr.dealloc(...)
> >> }
> >> 
> >> Another 'resource' might be adding an NSNotificationCenter observer, and 
> >> wanting to unobserve in deinit (no need in OS X 10.11, iOS 9, but for 
> >> earlier releases this is a valid example).
> >> 
> >> Changing the above code to use a 'defer' style deinit block might look 
> >> like:
> >> 
> >> init(count: Int = 0, ptr: UnsafeMutablePointer<T> = nil) {
> >>     self.count = count
> >>     self.space = count
> >> 
> >>     self.ptr = UnsafeMutablePointer<T>.alloc(count)
> >>     self.ptr.initializeFrom(ptr, count: count)
> >> 
> >>     deinit {
> >>         ptr.destroy(...)
> >>         ptr.dealloc(...)
> >>     }
> >> 
> >>     // NSNotificationCenter example too
> >>     NSNotificationCenter.defaultCenter().addObserver(...)
> >>     deinit { 
> >>         NSNotificationCenter.defaultCenter().removeObserver(...)
> >>     }
> >> }
> >> 
> >> The need to provide a separate implemention of deinit is gone. Reasoning 
> >> for 'defer' applies here. There is good locality between what was 
> >> initialized and what needs cleaning up.
> >> 
> >> Considerations:
> >> 1. Should deinit blocks be invoked before or after code in an explicit 
> >> deinit method?
> >> 2. Should deinit blocks be allowed in other methods; e.g. viewDidLoad()?
> >> 3. How should deinit blocks be prevented from strongly capturing self 
> >> (thus preventing themselves from ever running!)?
> > 

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

Reply via email to