I like the idea, I don’t like the potential to capture anything else though, or 
for instances to store closure references. It should offer similar performance 
to a standard `deinit`.

Instead, what about a sibling to `willSet`, `didSet` etc?

class Foo<T> {
  var ptr: UnsafeMutablePointer<T> {
    deinit {
      ptr.destroy(...)
      ptr.dealloc(...)
    }
  }

  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)
  }
}

That way you can have as many initializers as you like. It would be called when 
the object deinitializes only, and not when changing the property.

This could also hopefully be possible with property behaviours.

Patrick

> On 11 Jun 2016, at 9:45 AM, Erica Sadun via swift-evolution 
> <swift-evolution@swift.org> wrote:
> 
> 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@swift.org <mailto:swift-evolution@swift.org>> 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@swift.org <mailto:swift-evolution@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!)?
>> 
>> 
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to