[swift-evolution] Sketch: Teach init a 'defer'-like ability to deinit

Erica Sadun erica at ericasadun.com
Wed Jun 8 16:43:03 CDT 2016


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> 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>
> 
> 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!)?


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160608/ca9f5457/attachment.html>


More information about the swift-evolution mailing list