<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Jan 26, 2016, at 9:15 AM, Chris Eidhof via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">Now that we can return nil from a failable initializer without having initialized all the properties, it’s easier to make a mistake. For example, consider the following (artificial) code:<div class=""><br class=""></div><div class=""><div style="margin: 0px; line-height: normal; font-family: 'Akkurat TT';" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">class</span> MyArray<T> {</div><div style="margin: 0px; line-height: normal; font-family: 'Akkurat TT'; color: rgb(112, 61, 170);" class=""><span style="" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">var</span><span style="" class=""> pointer: </span>UnsafeMutablePointer<span style="" class=""><</span><span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">T</span><span style="" class="">></span></div><div style="margin: 0px; line-height: normal; font-family: 'Akkurat TT';" class=""> <span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">var</span> capacity: <span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">Int</span></div><div style="margin: 0px; line-height: normal; font-family: 'Akkurat TT'; min-height: 15px;" class=""> <br class="webkit-block-placeholder"></div><div style="margin: 0px; line-height: normal; font-family: 'Akkurat TT';" class=""> <span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">init</span>?(capacity: <span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">Int</span>) {</div><div style="margin: 0px; line-height: normal; font-family: 'Akkurat TT';" class=""> <span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">pointer</span> = <span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">UnsafeMutablePointer</span>.<span style="font-variant-ligatures: no-common-ligatures; color: #3d1d81" class="">alloc</span>(capacity)</div><div style="margin: 0px; line-height: normal; font-family: 'Akkurat TT';" class=""> <span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">if</span> capacity > <span style="font-variant-ligatures: no-common-ligatures; color: #272ad8" class="">100</span> {</div><div style="margin: 0px; line-height: normal; font-family: 'Akkurat TT'; color: rgb(0, 132, 0);" class=""><span style="" class=""> </span>// Here we should also free the memory. In other words, duplicate the code from deinit.</div><div style="margin: 0px; line-height: normal; font-family: 'Akkurat TT';" class=""> <span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">return</span> <span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">nil</span></div><div style="margin: 0px; line-height: normal; font-family: 'Akkurat TT';" class=""> }</div><div style="margin: 0px; line-height: normal; font-family: 'Akkurat TT';" class=""> <span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">self</span>.<span style="font-variant-ligatures: no-common-ligatures; color: #4f8187" class="">capacity</span> = capacity</div><div style="margin: 0px; line-height: normal; font-family: 'Akkurat TT'; min-height: 15px;" class=""> <br class="webkit-block-placeholder"></div><div style="margin: 0px; line-height: normal; font-family: 'Akkurat TT';" class=""> }</div><div style="margin: 0px; line-height: normal; font-family: 'Akkurat TT'; min-height: 15px;" class=""> <br class="webkit-block-placeholder"></div><div style="margin: 0px; line-height: normal; font-family: 'Akkurat TT';" class=""> <span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">deinit</span> {</div><div style="margin: 0px; line-height: normal; font-family: 'Akkurat TT'; color: rgb(79, 129, 135);" class=""><span style="" class=""> </span>pointer<span style="" class="">.</span><span style="font-variant-ligatures: no-common-ligatures; color: #3d1d81" class="">destroy</span><span style="" class="">(</span>capacity<span style="" class="">)</span></div><div style="margin: 0px; line-height: normal; font-family: 'Akkurat TT';" class=""> }</div><div style="margin: 0px; line-height: normal; font-family: 'Akkurat TT';" class="">}</div></div><div style="margin: 0px; line-height: normal; font-family: 'Akkurat TT';" class=""><br class=""></div><div style="margin: 0px; line-height: normal; font-family: 'Akkurat TT';" class="">In the `return nil` case, we should really free the memory allocated by the pointer. Or in other words, we need to duplicate the behavior from the deinit.</div><div style="margin: 0px; line-height: normal; font-family: 'Akkurat TT';" class=""><br class=""></div><div style="margin: 0px; line-height: normal; font-family: 'Akkurat TT';" class="">Before Swift 2.2, this mistake wasn’t possible, because we knew that we could count on deinit being called, *always*. With the current behavior, return `nil` is easier, but it does come at the cost of accidentally introducing bugs. As Joe Groff pointed out, a solution would be to have something like “deferOnError” (or in this case, “deferOnNil”), but that feels a bit heavy-weight to me (and you still have to duplicate code).</div><div style="margin: 0px; line-height: normal; font-family: 'Akkurat TT';" class=""><br class=""></div><div style="margin: 0px; line-height: normal; font-family: 'Akkurat TT';" class="">In any case, I think it’s nice that we can now return nil earlier. I don’t like that it goes at the cost of safety, but I realize it’s probably only making things less safe in a small amount of edge cases.</div></div></div></blockquote><br class=""></div><div>Let’s re-order the statements in your example:</div><div><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div><div><font face="Menlo" class="">class MyArray<T> {</font></div></div><div><div><font face="Menlo" class=""> var pointer: UnsafeMutablePointer<T></font></div></div><div><div><font face="Menlo" class=""> var capacity: Int</font></div></div><div><div><br class=""></div></div><div><div><font face="Menlo" class=""> init?(capacity: Int) {</font></div></div><div><div><span style="font-family: Menlo;" class=""> if capacity > 100 {</span></div></div><div><div><font face="Menlo" class=""> // Here we should also free the memory. In other words, duplicate the code from deinit.</font></div></div><div><div><font face="Menlo" class=""> return nil</font></div></div><div><div><font face="Menlo" class=""> }</font></div></div><div><div><font face="Menlo" class=""> self.capacity = capacity</font></div></div><div><div><div><font face="Menlo" class=""> pointer = UnsafeMutablePointer.alloc(capacity)</font></div></div><div></div><div><span style="font-family: Menlo;" class=""> }</span></div></div><div><div><font face="Menlo" class=""> </font></div></div><div><div><font face="Menlo" class=""> deinit {</font></div></div><div><div><font face="Menlo" class=""> pointer.destroy(capacity)</font></div></div><div><div><span style="font-family: Menlo;" class=""> }</span></div></div><div><div><font face="Menlo" class="">}</font></div></div></blockquote><div><div><br class=""></div><div>If the initializer returns ‘nil’ and we still call deinit, we end up destroying a pointer that was never allocated.</div><div><br class=""></div><div>If you come from an Objective-C background, you might expect implicit zeroing of the allocated block to help here. However, Swift doesn’t have that, because many Swift types don’t have a “zero” state that’s safe to destroy. For example, anything with a member of non-optional reference type, e.g.,</div><div><br class=""></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div><div><font face="Menlo" class="">class ClassWrapper {</font></div></div><div><div><font face="Menlo" class=""> var array: MyArray<String></font></div></div><div><div><font face="Menlo" class=""><br class=""></font></div></div><div><div><font face="Menlo" class=""> init(array: MyArray<String>) {</font></div></div><div><div><font face="Menlo" class=""> self.array = array</font></div></div><div><div><font face="Menlo" class=""> }</font></div><div><font face="Menlo" class=""><br class=""></font></div><div><font face="Menlo" class=""> deinit {</font></div><div><font face="Menlo" class=""> print(array) // array is a valid instance of MyArray<String></font></div><div><font face="Menlo" class=""> }</font></div></div><div><div><font face="Menlo" class="">}</font></div></div></blockquote><div><div><br class=""></div><div>A valid ClassWrapper instance will always have an instance of MyArray<String>, even throughout its deinitializer.</div><div><br class=""></div><div>The basic property here is that one cannot run a deinitializer on an instance that hasn’t been fully constructed (all the way up the class hierarchy).</div><div><br class=""></div></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>- Doug</div><div><br class=""></div><br class=""></body></html>