<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=""><font face="AvenirNext-Regular" class="">Yes, </font><font face="PT Mono" color="#008f00" class="">NSNumber</font><font face="AvenirNext-Regular" class=""> was a bad example. </font><span style="font-family: AvenirNext-Regular;" class="">Immutable types can implement it and do a shallow copy, as you said.</span><div class=""><font face="AvenirNext-Regular" class="">The </font><font face="PT Mono" color="#008f00" class="">NSCopying</font><font face="AvenirNext-Regular" class=""> protocol won’t do because:</font></div><div class=""><ul class="MailOutline"><li class=""><font face="AvenirNext-Regular" class="">It only works on </font><font face="PT Mono" color="#941751" class="">@objc</font><font face="AvenirNext-Regular" class=""> classes.</font></li><li class=""><font face="AvenirNext-Regular" class="">Its proper use is deprecated (namely, the use of provided </font><font face="PT Mono" color="#008f00" class="">NSZone</font><font face="AvenirNext-Regular" class=""> parameter is deprecated)</font><span style="font-family: AvenirNext-Regular;" class="">.</span></li><li class=""><font face="AvenirNext-Regular" class="">It’s in <b class="">Foundation</b> framework, which has nothing to do with Swift, per se.</font></li></ul><div class=""><span style="font-family: AvenirNext-Regular;" class=""><br class=""></span></div><div class=""><span style="font-family: AvenirNext-Regular;" class="">Besides, the <b class="">Foundation</b> framework is largely composed of outdated Objective-C code, which is a horrible fit for use in Swift.</span></div><div class=""><span style="font-family: AvenirNext-Regular;" class="">If you ask me, Swift needs to phase out its use of Foundation types in favor of faster, more convenient and generally more </span><b style="font-family: AvenirNext-Regular;" class="">swifty</b><span style="font-family: AvenirNext-Regular;" class=""> types.</span></div><div class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Jul 12, 2017, at 6:58 PM, Philippe Hausler <<a href="mailto:phausler@apple.com" class="">phausler@apple.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><br class="Apple-interchange-newline"><br class="" style="font-family: AvenirNext-Medium; font-size: 14px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><blockquote type="cite" class="" style="font-family: AvenirNext-Medium; font-size: 14px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;"><div class="">On Jul 12, 2017, at 3:23 AM, Gor Gyolchanyan 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=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;">Hello, swift community!<div class=""><br class=""></div><div class="">Recently I’ve come across a dilemma regarding value-type semantics when dealing with generic types.</div><div class="">Consider a protocol that has a mutating in-place function and a non-mutating returning variant of that function:</div><div class=""><br class=""></div><div class=""><font face="PT Mono" class=""><font color="#941751" class="">protocol</font><span class="Apple-converted-space"> </span><font color="#008f00" class="">Transmogrifier</font><span class="Apple-converted-space"> </span>{</font></div><div class=""><font face="PT Mono" class=""><br class=""></font></div><div class=""><font face="PT Mono" class=""> <span class="Apple-converted-space"> </span><font color="#941751" class="">mutating</font> <font color="#941751" class="">func</font><span class="Apple-converted-space"> </span>transmogrify()</font></div><div class=""><font face="PT Mono" class=""><br class=""></font></div><div class=""><font face="PT Mono" class=""> <font color="#941751" class="">func</font> transmogrified() -><span class="Apple-converted-space"> </span><font color="#941751" class="">Self</font></font></div><div class=""><font face="PT Mono" class=""><br class=""></font></div><div class=""><font face="PT Mono" class="">}</font></div><div class=""><br class=""></div><div class="">One of these methods has to have a default implementation in terms of the other.</div><div class=""><br class=""></div><div class="">One way doing it is to implement the mutating version in terms of non-mutating because it doesn’t depend on additional conditions to work, since assigning to `self` causes a complete copy of the internal state of the object regardless of whether it’s a value type or a reference type. However, this approach has a big downside: in many cases mutating functions mutate only part of the instance, which means that an efficient implementation will have to implement the mutating version and because of the way the default implementation works, the non-mutating version would also need to be manually implemented, which makes the default implementation useless in those cases.</div><div class=""><br class=""></div><div class="">Implementing the non-mutating version in terms of mutating version solves this problem nicely, allowing one to focus on mutating only the necessary parts of the instance, while leaving the need to return a separate instance to the default implementation, which would be perfectly adequate in most cases. This approach has its own problem that this pitch seeks to solve. The problem becomes apparent when you consider this naive implementation:</div><div class=""><br class=""></div><div class=""><font face="PT Mono" class=""><font color="#941751" class="">extension</font><span class="Apple-converted-space"> </span><font color="#008f00" class="">Transmogrifier</font><span class="Apple-converted-space"> </span>{</font></div><div class=""><font face="PT Mono" class=""><br class=""></font></div><div class=""><font face="PT Mono" class=""> <span class="Apple-converted-space"> </span><font color="#941751" class="">public</font><span class="Apple-converted-space"> </span><font color="#941751" class="">func</font> transmogrified() -><span class="Apple-converted-space"> </span><font color="#941751" class="">Self</font><span class="Apple-converted-space"> </span>{</font></div><div class=""><font face="PT Mono" class=""> <span class="Apple-converted-space"> </span><font color="#941751" class="">var</font><span class="Apple-converted-space"> </span>result =<span class="Apple-converted-space"> </span><font color="#941751" class="">self</font></font></div><div class=""><font face="PT Mono" class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>result.<font color="#005493" class="">transmogrify</font>()</font></div><div class=""><font face="PT Mono" class=""><span class="Apple-tab-span" style="white-space: pre;">        </span><font color="#941751" class="">return</font><span class="Apple-converted-space"> </span>result</font></div><div class=""><font face="PT Mono" class=""> }</font></div><div class=""><font face="PT Mono" class=""><br class=""></font></div><div class=""><font face="PT Mono" class="">}</font></div><div class=""><br class=""></div><div class="">The above implementation is only correct for value types, because assignment is a deep copy. If the instance is of a reference type, the assignment will do nothing and the call to the mutating version will apply to the original object, violating the postcondition of the function (which states that the function shall not modify the instance in any way).</div><div class=""><br class=""></div><div class="">The most straight-forward way of solving this problem is to introduce a new protocol for making sure the original instance is always copied:</div></div></div></blockquote><div style="font-family: AvenirNext-Medium; font-size: 14px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: AvenirNext-Medium; font-size: 14px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">Immutable types like NSString, NSDictionary etc just return self for the copy.</div><br class="" style="font-family: AvenirNext-Medium; font-size: 14px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><blockquote type="cite" class="" style="font-family: AvenirNext-Medium; font-size: 14px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><br class=""></div><div class=""><font face="PT Mono" class=""><font color="#941751" class="">protocol</font><span class="Apple-converted-space"> </span><font color="#008f00" class="">CopyInitializable</font><span class="Apple-converted-space"> </span>{</font></div><div class=""><font face="PT Mono" class=""><br class=""></font></div><div class=""><font face="PT Mono" class=""> <span class="Apple-converted-space"> </span><font color="#941751" class="">init</font>(copying other:<span class="Apple-converted-space"> </span><font color="#941751" class="">Self</font>)</font></div><div class=""><font face="PT Mono" class=""><br class=""></font></div><div class=""><font face="PT Mono" class="">}</font></div><div class=""><br class=""></div><div class="">In which case the default implementation becomes fully correct:</div><div class=""><br class=""></div><div class=""><div class=""><font face="PT Mono" color="#797979" class="">// The `CopyInitializable` conformance can also be moved to the protocol itself</font></div><div class=""><font color="#797979" class=""><font face="PT Mono" class="">// if the </font><span class="" style="font-family: 'PT Mono';">protocol conformance requires value-type semantics.</span></font></div><div class=""></div></div><div class=""><span class="" style="font-family: 'PT Mono';"><font color="#941751" class="">extension</font><span class="Apple-converted-space"> </span><font color="#008f00" class="">Transmogrifier</font><span class="Apple-converted-space"> </span><font color="#941751" class="">where</font><span class="Apple-converted-space"> </span><font color="#941751" class="">Self</font>:<span class="Apple-converted-space"> </span><font color="#008f00" class="">CopyInitializable</font><span class="Apple-converted-space"> </span>{</span></div><div class=""><div class=""><div class=""><span class="" style="font-family: 'PT Mono';"> </span></div></div><div class=""><font face="PT Mono" class=""> <span class="Apple-converted-space"> </span><font color="#941751" class="">public</font><span class="Apple-converted-space"> </span><font color="#941751" class="">func</font> transmogrified() -><span class="Apple-converted-space"> </span><font color="#941751" class="">Self</font><span class="Apple-converted-space"> </span>{</font></div><div class=""><font face="PT Mono" class=""> <span class="Apple-converted-space"> </span><font color="#941751" class="">var</font><span class="Apple-converted-space"> </span>result =<span class="Apple-converted-space"> </span><font color="#941751" class="">Self</font>(copying:<span class="Apple-converted-space"> </span><font color="#941751" class="">self</font>)</font></div><div class=""><font face="PT Mono" class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>result.<font color="#005493" class="">transmogrify</font>()</font></div><div class=""><font face="PT Mono" class=""><span class="Apple-tab-span" style="white-space: pre;">        </span><font color="#941751" class="">return</font><span class="Apple-converted-space"> </span>result</font></div><div class=""><font face="PT Mono" class=""> }</font></div><div class=""><font face="PT Mono" class=""><br class=""></font></div><div class=""><font face="PT Mono" class="">}</font></div></div><div class=""><br class=""></div><div class="">The downside of this approach is the need to manage<span class="Apple-converted-space"> </span><font face="PT Mono" color="#008f00" class="">CopyInitializable</font><span class="Apple-converted-space"> </span>conformance of the types that becomes extra hassle that seems to conflict with the behavior of value types.</div><div class=""><br class=""></div><div class="">This pitch proposes adding<span class="Apple-converted-space"> </span><font face="PT Mono" color="#008f00" class="">CopyInitializable</font><span class="Apple-converted-space"> </span>protocol to the swift standard library and having the compiler automatically generate conformance to it for all value types.</div><div class="">This would immediately solve all problems of correct convenient implementations of non-mutaiting variants of in-place functions as well as remove the hassle of having to manage conformance to<span class="Apple-converted-space"> </span><font face="PT Mono" color="#008f00" class="">CopyInitializable</font> for all value types that are guaranteed to have this behavior in the first place.</div><div class=""><font face="AvenirNext-Regular" class=""><br class=""></font></div><div class=""><font face="AvenirNext-Regular" class="">An good use case would be the<span class="Apple-converted-space"> </span></font><font face="PT Mono" color="#008f00" class="">NSNumber</font><font face="AvenirNext-Regular" class=""><span class="Apple-converted-space"> </span>class, which would conform to </font><font face="PT Mono" color="#008f00" class="">CopyInitializable</font> and make use of a single obvious mutating-to-nonmutating implementation of arithmetic operations that would work equally well on all standard numeric types.</div></div></div></blockquote><div style="font-family: AvenirNext-Medium; font-size: 14px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: AvenirNext-Medium; font-size: 14px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: AvenirNext-Medium; font-size: 14px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">NSNumber is an immutable reference type, so copy just returns a strong reference to itself. So how would a copy initialization of a NSNumber add any value? If we were to add a copy initializer to NSNumber, it would probably be implemented as just replacing self in the init with the other object.</div><div style="font-family: AvenirNext-Medium; font-size: 14px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: AvenirNext-Medium; font-size: 14px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">For reference types there is already a protocol for what you are attempting to do; NSCopying (granted it probably should have a Self return instead of Any… but that is a different can-o-worms).</div><br class="" style="font-family: AvenirNext-Medium; font-size: 14px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><blockquote type="cite" class="" style="font-family: AvenirNext-Medium; font-size: 14px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><font face="AvenirNext-Regular" class=""><br class=""></font></div><div class=""><font face="AvenirNext-Regular" class="">I’d like to hear opinions regarding this pitch and in case of consensus, I’d write an official proposal and offer it for review.</font></div><div class=""><font face="AvenirNext-Regular" class=""><br class=""></font></div><div class="">Regards,</div><div class="">Gor Gyolchanyan.</div><div class=""><br class=""></div></div>_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a></div></blockquote></div></blockquote></div><br class=""></div></div></body></html>