<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><br class=""><div><br class=""><blockquote type="cite" class=""><div class="">On Aug 6, 2017, at 12:58 PM, Charles Srstka &lt;<a href="mailto:cocoadev@charlessoft.com" class="">cocoadev@charlessoft.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><blockquote type="cite" class="" style="font-family: SFHello-Regular; font-size: 12px; 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;">On Aug 3, 2017, at 12:05 PM, Itai Ferber via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; wrote:<br class=""></blockquote><div style="font-family: SFHello-Regular; font-size: 12px; 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=""><blockquote type="cite" class=""><br class="Apple-interchange-newline"><div class=""><span class="" style="font-family: Helvetica; font-size: 12px; 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; float: none; display: inline !important;">Thanks for putting these thoughts together, Jordan! Some additional comments inline.</span><br class="" style="font-family: Helvetica; font-size: 12px; 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;"><div class="" style="font-family: Helvetica; font-size: 12px; 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;"><br class=""><blockquote type="cite" class=""><div class="">On Aug 2, 2017, at 5:08 PM, Jordan Rose &lt;<a href="mailto:jordan_rose@apple.com" class="">jordan_rose@apple.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space;">David Hart&nbsp;<a href="https://twitter.com/dhartbit/status/891766239340748800" class="">recently asked on Twitter</a>&nbsp;if there was a good way to add Decodable support to somebody else's class. The short answer is "no, because you don't control all the subclasses", but David already understood that and wanted to know if there was anything working to mitigate the problem. So I decided to write up a long email about it instead. (Well, actually I decided to write a short email and then failed at doing so.)<div class=""><br class=""></div><div class=""><b class="">The Problem</b></div><div class=""><br class=""></div><div class="">You can add Decodable to someone else's struct today with no problems:<div class=""><br class=""></div><blockquote class="" style="margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; color: rgb(186, 45, 162); background-color: rgb(255, 255, 255);"><font face="Menlo" class="">extension<span class=""><span class="Apple-converted-space">&nbsp;</span></span><span class="" style="color: rgb(79, 129, 135);">Point</span><span class="">:<span class="Apple-converted-space">&nbsp;</span></span><span class="" style="color: rgb(112, 61, 170);">Decodable</span><span class=""><span class="Apple-converted-space">&nbsp;</span>{</span></font></div><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);"><font face="Menlo" class="">&nbsp;<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(186, 45, 162);">enum</span><span class="Apple-converted-space">&nbsp;</span>CodingKeys:<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(112, 61, 170);">String</span>,<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(112, 61, 170);">CodingKey</span><span class="Apple-converted-space">&nbsp;</span>{</font></div><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);"><font face="Menlo" class="">&nbsp; &nbsp;<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(186, 45, 162);">case</span><span class="Apple-converted-space">&nbsp;</span>x</font></div><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);"><font face="Menlo" class="">&nbsp; &nbsp;<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(186, 45, 162);">case</span><span class="Apple-converted-space">&nbsp;</span>y</font></div><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);"><font face="Menlo" class="">&nbsp; }</font></div><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);"><font face="Menlo" class="">&nbsp;<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(186, 45, 162);">public</span><span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(186, 45, 162);">init</span>(from decoder:<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(112, 61, 170);">Decoder</span>)<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(186, 45, 162);">throws</span><span class="Apple-converted-space">&nbsp;</span>{</font></div><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);"><font face="Menlo" class="">&nbsp; &nbsp;<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(186, 45, 162);">let</span><span class="Apple-converted-space">&nbsp;</span>container =<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(186, 45, 162);">try</span><span class="Apple-converted-space">&nbsp;</span>decoder.<span class="" style="color: rgb(62, 30, 129);">container</span>(keyedBy:<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(79, 129, 135);">CodingKeys</span>.<span class="" style="color: rgb(186, 45, 162);">self</span>)</font></div><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);"><font face="Menlo" class="">&nbsp; &nbsp;<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(186, 45, 162);">let</span><span class="Apple-converted-space">&nbsp;</span>x =<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(186, 45, 162);">try</span><span class="Apple-converted-space">&nbsp;</span>container.<span class="" style="color: rgb(62, 30, 129);">decode</span>(<span class="" style="color: rgb(112, 61, 170);">Double</span>.<span class="" style="color: rgb(186, 45, 162);">self</span>, forKey: .<span class="" style="color: rgb(49, 89, 93);">x</span>)</font></div><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);"><font face="Menlo" class="">&nbsp; &nbsp;<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(186, 45, 162);">let</span><span class="Apple-converted-space">&nbsp;</span>y =<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(186, 45, 162);">try</span><span class="Apple-converted-space">&nbsp;</span>container.<span class="" style="color: rgb(62, 30, 129);">decode</span>(<span class="" style="color: rgb(112, 61, 170);">Double</span>.<span class="" style="color: rgb(186, 45, 162);">self</span>, forKey: .<span class="" style="color: rgb(49, 89, 93);">y</span>)</font></div><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);"><font face="Menlo" class="">&nbsp; &nbsp;<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(186, 45, 162);">self</span>.<span class="" style="color: rgb(186, 45, 162);">init</span>(x: x, y: y)</font></div><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);"><font face="Menlo" class="">&nbsp; }</font></div><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);"><font face="Menlo" class="">}</font></div></blockquote><br class=""><div class="">But if Point is a (non-final) class, then this gives you a pile of errors:</div><div class=""><br class=""></div><div class="">- init(from:) needs to be 'required' to satisfy a protocol requirement. 'required' means the initializer can be invoked dynamically on subclasses. Why is this important? Because someone might write code like this:</div><div class=""><br class=""></div><blockquote class="" style="margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);"><font face="Menlo" class=""><span class="" style="color: rgb(186, 45, 162);">func</span><span class="Apple-converted-space">&nbsp;</span>decodeMe&lt;Result:<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(112, 61, 170);">Decodable</span>&gt;() -&gt;<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(112, 61, 170);">Result</span><span class="Apple-converted-space">&nbsp;</span>{</font></div><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);"><font face="Menlo" class="">&nbsp;<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(186, 45, 162);">let</span><span class="Apple-converted-space">&nbsp;</span>decoder = getDecoderFromSomewhere()</font></div><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);"><font face="Menlo" class="">&nbsp;<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(186, 45, 162);">return</span><span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(112, 61, 170);">Result</span>(from: decoder)</font></div><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);"><font face="Menlo" class="">}</font></div><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);"><font face="Menlo" class=""><span class="" style="color: rgb(186, 45, 162);">let</span><span class="Apple-converted-space">&nbsp;</span>specialPoint:<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(112, 61, 170);">VerySpecialSubclassOfPoint</span><span class="Apple-converted-space">&nbsp;</span>= decodeMe()</font></div></blockquote><br class=""><div class="">…and the compiler can't stop them, because&nbsp;VerySpecialSubclassOfPoint is a Point, and Point is Decodable, and therefore&nbsp;VerySpecialSubclassOfPoint is Decodable. A bit more on this later, but for now let's say that's a sensible requirement.</div><div class=""><br class=""></div><div class="">- init(from:) also has to be a 'convenience' initializer. That one makes sense too—if you're outside the module, you can't necessarily see private properties, and so of course you'll have to call another initializer that can.</div><div class=""><br class=""></div><div class="">But once it's marked 'convenience' and 'required' we get "'required' initializer must be declared directly in class 'Point' (not in an extension)", and that defeats the whole purpose. Why this restriction?</div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><b class="">The Semantic Reason</b></div><div class=""><b class=""><br class=""></b></div><div class="">The initializer is 'required', right? So all subclasses need to have access to it. But the implementation we provided here might not make sense for all subclasses—what if&nbsp;VerySpecialSubclassOfPoint doesn't have an 'init(x:y:)' initializer? Normally, the compiler checks for this situation and makes the subclass reimplement the 'required' initializer…but that only works if the 'required' initializers are all known up front. So it can't allow this new 'required' initializer to go by, because someone might try to call it dynamically on a subclass. Here's a dynamic version of the code from above:</div><div class=""><br class=""></div><blockquote class="" style="margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);"><font face="Menlo" class=""><span class="" style="color: rgb(186, 45, 162);">func</span>&nbsp;decodeDynamic(<span class="" style="color: rgb(186, 45, 162);">_</span>&nbsp;pointType:&nbsp;<span class="" style="color: rgb(112, 61, 170);">Point</span>.Type) -&gt;&nbsp;<span class="" style="color: rgb(112, 61, 170);">Point</span>&nbsp;{</font></div><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);"><font face="Menlo" class="">&nbsp;&nbsp;<span class="" style="color: rgb(186, 45, 162);">let</span>&nbsp;decoder = getDecoderFromSomewhere()</font></div><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);"><font face="Menlo" class="">&nbsp;&nbsp;<span class="" style="color: rgb(186, 45, 162);">return</span>&nbsp;pointType.<span class="" style="color: rgb(186, 45, 162);">init</span>(from: decoder)</font></div><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);"><font face="Menlo" class="">}</font></div><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);"><font face="Menlo" class=""><span class="" style="color: rgb(186, 45, 162);">let</span>&nbsp;specialPoint = decodeDynamic(VerySpecialSubclassOfPoint.<span class="" style="color: rgb(186, 45, 162);">self</span>)</font></div></blockquote><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><b class="">The Implementation Reason</b></div><div class=""><b class=""><br class=""></b></div><div class="">'required' initializers are like methods: they may require dynamic dispatch. That means that they get an entry in the class's dynamic dispatch table, commonly known as its<span class="Apple-converted-space">&nbsp;</span><i class="">vtable</i>. Unlike Objective-C method tables, vtables aren't set up to have entries arbitrarily added at run time.</div><div class=""><br class=""></div><div class="">(Aside: This is one of the reasons why non-@objc methods in Swift extensions can't be overridden; if we ever lift that restriction, it'll be by using a separate table and a form of dispatch similar to objc_msgSend. I sent a proposal to swift-evolution about this last year but there wasn't much interest.)</div></div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><b class="">The Workaround</b></div><div class=""><b class=""><br class=""></b></div><div class="">Today's answer isn't wonderful, but it does work: write a wrapper struct that conforms to Decodable instead:</div><div class=""><br class=""></div><blockquote class="" style="margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div class=""><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);"><font face="Menlo" class=""><span class="" style="color: rgb(186, 45, 162);">struct</span><span class="Apple-converted-space">&nbsp;</span>DecodedPoint:<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(112, 61, 170);">Decodable</span><span class="Apple-converted-space">&nbsp;</span>{</font></div></div><div class=""><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);"><font face="Menlo" class="">&nbsp;<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(186, 45, 162);">var</span><span class="Apple-converted-space">&nbsp;</span>value:<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(79, 129, 135);">Point</span></font></div></div><div class=""><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);"><font face="Menlo" class="">&nbsp;<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(186, 45, 162);">enum</span><span class="Apple-converted-space">&nbsp;</span>CodingKeys:<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(112, 61, 170);">String</span>,<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(112, 61, 170);">CodingKey</span><span class="Apple-converted-space">&nbsp;</span>{</font></div></div><div class=""><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);"><font face="Menlo" class="">&nbsp; &nbsp;<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(186, 45, 162);">case</span><span class="Apple-converted-space">&nbsp;</span>x</font></div></div><div class=""><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);"><font face="Menlo" class="">&nbsp; &nbsp;<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(186, 45, 162);">case</span><span class="Apple-converted-space">&nbsp;</span>y</font></div></div><div class=""><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);"><font face="Menlo" class="">&nbsp; }</font></div></div><div class=""><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);"><font face="Menlo" class="">&nbsp;<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(186, 45, 162);">public</span><span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(186, 45, 162);">init</span>(from decoder:<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(112, 61, 170);">Decoder</span>)<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(186, 45, 162);">throws</span><span class="Apple-converted-space">&nbsp;</span>{</font></div></div><div class=""><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);"><font face="Menlo" class="">&nbsp; &nbsp;<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(186, 45, 162);">let</span><span class="Apple-converted-space">&nbsp;</span>container =<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(186, 45, 162);">try</span><span class="Apple-converted-space">&nbsp;</span>decoder.<span class="" style="color: rgb(62, 30, 129);">container</span>(keyedBy:<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(79, 129, 135);">CodingKeys</span>.<span class="" style="color: rgb(186, 45, 162);">self</span>)</font></div></div><div class=""><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);"><font face="Menlo" class="">&nbsp; &nbsp;<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(186, 45, 162);">let</span><span class="Apple-converted-space">&nbsp;</span>x =<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(186, 45, 162);">try</span><span class="Apple-converted-space">&nbsp;</span>container.<span class="" style="color: rgb(62, 30, 129);">decode</span>(<span class="" style="color: rgb(112, 61, 170);">Double</span>.<span class="" style="color: rgb(186, 45, 162);">self</span>, forKey: .<span class="" style="color: rgb(49, 89, 93);">x</span>)</font></div></div><div class=""><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);"><font face="Menlo" class="">&nbsp; &nbsp;<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(186, 45, 162);">let</span><span class="Apple-converted-space">&nbsp;</span>y =<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(186, 45, 162);">try</span><span class="Apple-converted-space">&nbsp;</span>container.<span class="" style="color: rgb(62, 30, 129);">decode</span>(<span class="" style="color: rgb(112, 61, 170);">Double</span>.<span class="" style="color: rgb(186, 45, 162);">self</span>, forKey: .<span class="" style="color: rgb(49, 89, 93);">y</span>)</font></div></div><div class=""><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);"><font face="Menlo" class="">&nbsp; &nbsp;<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(186, 45, 162);">self</span>.<span class="" style="color: rgb(79, 129, 135);">value</span><span class="Apple-converted-space">&nbsp;</span>=<span class="Apple-converted-space">&nbsp;</span><span class="" style="color: rgb(79, 129, 135);">Point</span>(x: x, y: y)</font></div></div><div class=""><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);"><font face="Menlo" class="">&nbsp; }</font></div></div><div class=""><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);"><font face="Menlo" class="">}</font></div></div></blockquote><div class=""><br class=""></div><div class="">This doesn't have any of the problems with inheritance, because it only handles the base class, Point. But it makes everywhere else a little less convenient—instead of directly encoding or decoding Point, you have to use the wrapper, and that means no implicitly-generated Codable implementations either.</div><div class=""><br class=""></div><div class="">I'm not going to spend more time talking about this, but it is the officially recommended answer at the moment. You can also just have all your own types that contain points manually decode the 'x' and 'y' values and then construct a Point from that.</div></div></div></blockquote><div class="">I would actually take this a step further and recommend that<span class="Apple-converted-space">&nbsp;</span><i class="">any</i>&nbsp;time you intend to extend someone else’s type with<span class="Apple-converted-space">&nbsp;</span><font face="SFMono-Regular" class="">Encodable</font><span class="Apple-converted-space">&nbsp;</span>or<span class="Apple-converted-space">&nbsp;</span><font face="SFMono-Regular" class="">Decodable</font>, you should almost certainly write a wrapper struct for it instead, unless you have reasonable guarantees that the type will<span class="Apple-converted-space">&nbsp;</span><i class="">never</i>&nbsp;attempt to conform to these protocols on its own.</div><div class=""><br class=""></div><div class="">This might sound extreme (and inconvenient), but Jordan mentions the issue here below in&nbsp;<b class="">The Dangers of Retroactive Modeling</b><span class="">. Any time you conform a type which does not belong to you to a protocol, you make a decision about its behavior where you might not necessarily have the "right" to — if the type later adds conformance to the protocol itself (e.g. in a library update), your code will no longer compile, and you’ll have to remove your own conformance. In most cases, that’s fine, e.g., there’s not much harm done in dropping your custom<span class="Apple-converted-space">&nbsp;</span><font face="SFMono-Regular" class="">Equatable</font><span class="Apple-converted-space">&nbsp;</span>conformance on some type if it starts adopting it on its own. The real risk with<span class="Apple-converted-space">&nbsp;</span><font face="SFMono-Regular" class="">Encodable</font><span class="Apple-converted-space">&nbsp;</span>and<span class="Apple-converted-space">&nbsp;</span><font face="SFMono-Regular" class="">Decodable</font><span class="Apple-converted-space">&nbsp;</span>is that unless you don’t care about backwards/forwards compatibility, the<span class="Apple-converted-space">&nbsp;</span><i class="">implementations of these conformances are forever</i>.</span></div><div class=""><span class=""><br class=""></span></div><div class="">Using<span class="Apple-converted-space">&nbsp;</span><font face="SFMono-Regular" class="">Point</font><span class="Apple-converted-space">&nbsp;</span>here as an example, it’s not unreasonable for<span class="Apple-converted-space">&nbsp;</span><font face="SFMono-Regular" class="">Point</font><span class="Apple-converted-space">&nbsp;</span>to eventually get updated to conform to<span class="Apple-converted-space">&nbsp;</span><font face="SFMono-Regular" class="">Codable</font>. It’s also not unreasonable for the implementation of<span class="Apple-converted-space">&nbsp;</span><font face="SFMono-Regular" class="">Point</font><span class="Apple-converted-space">&nbsp;</span>to adopt the default conformance, i.e., get encoded as<span class="Apple-converted-space">&nbsp;</span><font face="SFMono-Regular" class="">{"x": …, "y": …}</font>. This form might not be the most compact, but it leaves room for expansion (e.g. if<span class="Apple-converted-space">&nbsp;</span><font face="SFMono-Regular" class="">Point</font><span class="Apple-converted-space">&nbsp;</span>adds a<span class="Apple-converted-space">&nbsp;</span><font face="SFMono-Regular" class="">z</font><span class="Apple-converted-space">&nbsp;</span>field, which might also be reasonable, considering the type doesn’t belong to you). If you update your library dependency with the new<span class="Apple-converted-space">&nbsp;</span><font face="SFMono-Regular" class="">Point</font><span class="Apple-converted-space">&nbsp;</span>class and have to drop the conformance you added to it directly, you’ve introduced a backwards and forwards compatibility concern: all new versions of your app now encode and decode a new archive format, which now requires migration. Unless you don’t care about other versions of your app, you’ll have to deal with this:</div><div class=""><ol class="MailOutline"><li class="">Old versions of your app which users may have on their devices cannot read archives with this new format</li><li class="">New versions of your app cannot read archives with the old format</li></ol><div class=""><br class=""></div><div class="">Unless you don’t care for some reason, you will now have to write the wrapper struct, to either</div><div class=""><ol class="MailOutline"><li class="">Have new versions of your app attempt to read old archive versions and migrate them forward (leaving old app versions in the dust), or</li><li class="">Write all new archives with the old format so old app versions can still read archives written with newer app versions, and vice versa</li></ol><div class=""><br class=""></div></div><div class="">Either way, you’ll need to write some wrapper to handle this; it’s significantly safer to do that work up front on a type which you<span class="Apple-converted-space">&nbsp;</span><i class="">do</i>&nbsp;control (and safely allow<span class="Apple-converted-space">&nbsp;</span><font face="SFMono-Regular" class="">Point</font><span class="Apple-converted-space">&nbsp;</span>to change out underneath you transparently), rather than potentially end up between a rock and a hard place later on because a type you don’t own changes out from under you.</div></div></div></div></blockquote></div><br class="" style="font-family: SFHello-Regular; font-size: 12px; 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;"><div class="" style="font-family: SFHello-Regular; font-size: 12px; 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;">I should point out that there’s a third case: the case where you want to add conformance to a type from another framework,<span class="Apple-converted-space">&nbsp;</span><i class="">but you own both frameworks</i>.</div><div class="" style="font-family: SFHello-Regular; font-size: 12px; 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;"><br class=""></div><div class="" style="font-family: SFHello-Regular; font-size: 12px; 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;">Plenty of examples of this can be found in the Cocoa frameworks, actually. For example, as NSString is, of course, declared in Foundation, its original declaration cannot conform to the NSPasteboardReading protocol, which is declared in AppKit. As a result, Apple declares NSString’s NSPasteboardReading support in a category in AppKit. There are reasons one might want to do the same thing in their own code—make one library and/or framework for use with Foundation-only programs, and extend a type from that library/framework with NSPasteboardReading support in a separate framework. It can’t currently be done with Swift, though.</div><div class="" style="font-family: SFHello-Regular; font-size: 12px; 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;"><br class=""></div><div class="" style="font-family: SFHello-Regular; font-size: 12px; 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;">Charles</div></div></div></blockquote>Yes, you’re right; this is something we need to do in some cases. For <font face="SFMono-Regular" class="">Codable</font> specifically, I don’t think this design pattern would affect much, since:</div><div><ol class="MailOutline"><li class="">Encoded representations of values almost overwhelmingly only need to encode stored properties; computed properties are very rarely part of encoded state (what do you do with a computed property on decode?)</li><li class="">Extensions in Swift cannot add storage, so you can’t extend your own types elsewhere with new properties that would need to encoded</li></ol></div><br class=""><div class="">I think I’d be hard-pressed to find a case where it’s not possible to adopt <font face="SFMono-Regular" class="">Codable</font> on a type inside the framework it’s defined within due to a needed extension provided in a different framework (especially so considering <font face="SFMono-Regular" class="">Codable</font> comes from the stdlib, so it’s not like there are compatibility/platform concerns there).</div><div class=""><br class=""></div><div class="">Regardless, if you own the type completely, then of course it’s safe to extend and control your own <font face="SFMono-Regular" class="">Codable</font> implementation, and a <font face="SFMono-Regular" class="">struct</font> wrapper is unnecessary.</div><div class=""><br class=""></div></body></html>