<div dir="ltr">On Fri, Jun 10, 2016 at 9:55 PM, Jonathan Hull via swift-evolution <span dir="ltr"><<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>></span> wrote:<br><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div>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.</div><div><br></div><div>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.</div><div><br></div><div>I might spell it ‘deferToDeinit’ or 'deferUntilDeinit'</div><div><br></div><div>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?</div></div></blockquote><div><br></div><div>I really like this idea as well. Does it need to be a regular closure? This is one of those things that can be built into the language itself, surely? Then the implicitly unowned self part would be taken care of...</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div><br></div><div>Thanks,</div><div>Jon</div><div><blockquote type="cite"><pre style="white-space:pre-wrap;background-color:rgb(255,255,255)"><span class="">Twitter tl;dr:
><i> Brent: So each instance must remember which init was used for it and then run the matching deinit code at deinit time?
</i>><i> Me: In my version, the constructive act and destructive act are always paired, even redundantly, using a stack if needed
</i>><i> Graham: so all your deferredDeinit blocks would run, no matter which init was invoked?
</i>><i> 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) }
</i></span>
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
><i> On Jun 8, 2016, at 3:43 PM, Erica Sadun via swift-evolution <<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" target="_blank">swift-evolution at swift.org</a>> wrote:
</i><span class="">><i>
</i>><i> I really like this idea. Spatially moving cleanup next to unsafe operations is good practice.
</i>><i>
</i>><i> In normal code, I want my cleanup to follow as closely as possible to my unsafe act:
</i>><i>
</i>><i> let buffer: UnsafeMutablePointer<CChar> = UnsafeMutablePointer(allocatingCapacity: chunkSize)
</i>><i> defer { buffer.deallocateCapacity(chunkSize) }
</i>><i>
</i>><i> (Sorry for the horrible example, but it's the best I could grep up with on a moment's notice)
</i>><i>
</i>><i> 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
</i>><i>
</i>><i> self.ptr = UnsafeMutablePointer<T>(allocatingCapacity: count)
</i>><i> deferringDeInit { self.ptr.deallocateCapacity(count) }
</i>><i>
</i>><i> Or something.
</i>><i>
</i>><i> -- E
</i>><i> p.s. Normally I put them on the same line with a semicolon but dang these things can be long
</i>><i>
</i></span><span class="">>><i> On Jun 8, 2016, at 10:54 AM, Graham Perks via swift-evolution <<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" target="_blank">swift-evolution at swift.org</a> <mailto:<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" target="_blank">swift-evolution at swift.org</a>>> wrote:
</i>>><i>
</i>>><i> Teach init a 'defer'-like ability to deinit
</i>>><i>
</i>>><i> '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.
</i>>><i>
</i>>><i> Swift offers no support for resources acquired during 'init'.
</i>>><i>
</i></span>>><i> For an example, from <a href="https://www.mikeash.com/pyblog/friday-qa-2015-04-17-lets-build-swiftarray.html" target="_blank">https://www.mikeash.com/pyblog/friday-qa-2015-04-17-lets-build-swiftarray.html</a> <<a href="https://www.mikeash.com/pyblog/friday-qa-2015-04-17-lets-build-swiftarray.html" target="_blank">https://www.mikeash.com/pyblog/friday-qa-2015-04-17-lets-build-swiftarray.html</a>>
</i><div><div class="h5">>><i>
</i>>><i> init(count: Int = 0, ptr: UnsafeMutablePointer<T> = nil) {
</i>>><i> self.count = count
</i>>><i> self.space = count
</i>>><i>
</i>>><i> self.ptr = UnsafeMutablePointer<T>.alloc(count)
</i>>><i> self.ptr.initializeFrom(ptr, count: count)
</i>>><i> }
</i>>><i>
</i>>><i> deinit {
</i>>><i> ptr.destroy(...)
</i>>><i> ptr.dealloc(...)
</i>>><i> }
</i>>><i>
</i>>><i> 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).
</i>>><i>
</i>>><i> Changing the above code to use a 'defer' style deinit block might look like:
</i>>><i>
</i>>><i> init(count: Int = 0, ptr: UnsafeMutablePointer<T> = nil) {
</i>>><i> self.count = count
</i>>><i> self.space = count
</i>>><i>
</i>>><i> self.ptr = UnsafeMutablePointer<T>.alloc(count)
</i>>><i> self.ptr.initializeFrom(ptr, count: count)
</i>>><i>
</i>>><i> deinit {
</i>>><i> ptr.destroy(...)
</i>>><i> ptr.dealloc(...)
</i>>><i> }
</i>>><i>
</i>>><i> // NSNotificationCenter example too
</i>>><i> NSNotificationCenter.defaultCenter().addObserver(...)
</i>>><i> deinit {
</i>>><i> NSNotificationCenter.defaultCenter().removeObserver(...)
</i>>><i> }
</i>>><i> }
</i>>><i>
</i>>><i> 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.
</i>>><i>
</i>>><i> Considerations:
</i>>><i> 1. Should deinit blocks be invoked before or after code in an explicit deinit method?
</i>>><i> 2. Should deinit blocks be allowed in other methods; e.g. viewDidLoad()?
</i>>><i> 3. How should deinit blocks be prevented from strongly capturing self (thus preventing themselves from ever running!)?
</i>><i> </i></div></div></pre></blockquote><div><br></div></div></div><br>_______________________________________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
<br></blockquote></div><br></div></div>