<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 Jan 3, 2018, at 6:45 PM, Slava Pestov <<a href="mailto:spestov@apple.com" class="">spestov@apple.com</a>> wrote:</div><div class=""><div 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;" class=""><blockquote type="cite" class=""><div class="">On Jan 3, 2018, at 5:33 PM, Hooman Mehr <<a href="mailto:hooman@mac.com" class="">hooman@mac.com</a>> wrote:</div><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;">Thank you Slava, it is a very insightful answer. <div class="">It also reveals a potential source for hard to track bugs. To make it easier to see, lets add state to class C:</div><div class=""><br class=""></div><div class=""><div class="" style="margin: 0px; font-stretch: normal; font-size: 11px; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);"><span class="" style="color: rgb(186, 45, 162);">class</span><span class="Apple-converted-space"> </span>D:<span class="Apple-converted-space"> </span><span class="" style="color: rgb(79, 129, 135);">C</span><span class="Apple-converted-space"> </span>{<span class="Apple-converted-space"> </span><span class="" style="color: rgb(186, 45, 162);">var</span><span class="Apple-converted-space"> </span>state =<span class="Apple-converted-space"> </span><span class="" style="color: rgb(39, 42, 216);">0</span><span class="Apple-converted-space"> </span>}</div><div class="" style="margin: 0px; font-stretch: normal; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(0, 132, 0); background-color: rgb(255, 255, 255);"><span class="" style="color: rgb(186, 45, 162);">var</span><span class=""><span class="Apple-converted-space"> </span>d =<span class="Apple-converted-space"> </span></span><span class="" style="color: rgb(79, 129, 135);">D</span><span class="">()<span class="Apple-converted-space"> </span></span>// Bad but common habit of declaring objects as var</div><div class="" style="margin: 0px; font-stretch: normal; font-size: 11px; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);"><span class="" style="color: rgb(186, 45, 162);">for</span><span class="Apple-converted-space"> </span>i<span class="Apple-converted-space"> </span><span class="" style="color: rgb(186, 45, 162);">in</span><span class="Apple-converted-space"> </span><span class="" style="color: rgb(39, 42, 216);">1</span>...<span class="" style="color: rgb(39, 42, 216);">5</span><span class="Apple-converted-space"> </span>{<span class="Apple-converted-space"> </span><span class="" style="color: rgb(79, 129, 135);">d</span>.<span class="" style="color: rgb(49, 89, 93);">f</span>(i);<span class="Apple-converted-space"> </span><span class="" style="color: rgb(79, 129, 135);">d</span>.<span class="" style="color: rgb(79, 129, 135);">state</span><span class="Apple-converted-space"> </span>+=<span class="Apple-converted-space"> </span><span class="" style="color: rgb(39, 42, 216);">1</span><span class="Apple-converted-space"> </span>}</div><div class="" style="margin: 0px; font-stretch: normal; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(0, 132, 0); background-color: rgb(255, 255, 255);"><span class="" style="color: rgb(62, 30, 129);">print</span><span class="">(</span><span class="" style="color: rgb(79, 129, 135);">d</span><span class="">.</span><span class="" style="color: rgb(79, 129, 135);">state</span><span class="">)<span class="Apple-converted-space"> </span></span>// Prints 1</div></div><div class=""><br class=""></div><div class="">The result is surprising because a typical programmer does not expect an object to have mutating methods (that replace the object itself with a different one).</div><div class="">I think this is a bug in Swift compiler. It should not let a class “inherit” a mutating method in this manner. Compiler should require a non-mutating declaration of `f()` to satisfy `P` conformance for a class type.</div></div></div></blockquote><div class=""><br class=""></div><div class="">Perhaps, but it’s also possible to define a mutating method g() in a protocol extension of P, where g() is not a protocol requirement. Calling g() on a class instance can “replace” self in this manner also.</div></div></div></blockquote><div><br class=""></div><div>Is this desirable? It seems that Swift compiler generally tries to prevent you from defining mutating methods on class types and this situation feels like a flaw/bug that needs fixing. I think this can even have security implications (letting a malicious coder obfuscate a code put in place to create a backdoor).</div><br class=""><blockquote type="cite" class=""><div class=""><div 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;" class=""><blockquote type="cite" class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;"><div class="">If we fix the above, it should be possible to do what I asked in my post: When compiler knows an existential is an object, it should know all methods are non-mutating and accept `let` declaration despite calls to nominally mutating methods. Also, if a protocol refines another protocol to be class-bound, compiler should automatically refine all of its inherited mutating methods to be non-mutating and allow `let` declaration of an existential of that protocol even if there are calls to those originally mutating methods. </div></div></blockquote><div class=""><br class=""></div>This will prevent you from defining default implementations of protocol requirements in protocol extensions, which would be a source-breaking change at this point. I don’t think we can make such a change now.</div></div></blockquote><div><br class=""></div><div>I don’t think a <i class="">mutating</i> default implementation makes any sense for a class type. I think we should handle default implementation for class type with a constrained/refined extension that provides a non-mutating default implementation for the cases when a class type conforms to a non-class bound protocol. This seems to be impossible at the moment, but I see it as another shortcoming in the compiler, not a source breaking change for the sake of providing an obscure new feature.</div><br class=""><blockquote type="cite" class=""><div class=""><div 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;" class=""><br class=""></div><div 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;" class="">Slava</div><div 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;" class=""><br class=""><blockquote type="cite" class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;"><div class=""><br class=""></div><div class="">Hooman</div><div class=""><br class=""></div><div class=""><div class=""><blockquote type="cite" class=""><div class="">On Dec 21, 2017, at 10:59 PM, Slava Pestov <<a href="mailto:spestov@apple.com" class="">spestov@apple.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;">Hi Hooman,<div class=""><br class=""></div><div class="">Since the protocol P is not class-bounded, the requirement can be witnessed by a protocol extension method which re-assigns ‘self’:</div><div class=""><br class=""></div><div class="">protocol Initable {</div><div class=""> init()</div><div class="">}</div><div class=""><br class=""></div><div class="">extension P where Self : Initable {</div><div class=""> mutating func f(_ x: Int) -> Int {</div><div class=""> self = Self()</div><div class=""> return x</div><div class=""> }</div><div class="">}</div><div class=""><br class=""></div><div class="">class C : P, Initable {</div><div class=""> required init() {}</div><div class="">}</div><div class=""><br class=""></div><div class="">Now imagine you could do this,</div><div class=""><br class=""></div><div class="">let x: P & AnyObject</div><div class=""><br class=""></div><div class="">x.f(12)</div><div class=""><br class=""></div><div class="">This would be invalid because ‘x’ is a let binding but the requirement ‘f’ is witnessed by the protocol extension method, which performs a mutating access of ‘self’.</div><div class=""><br class=""></div><div class="">Slava</div><div class=""><div class=""><br class=""><blockquote type="cite" class=""><div class="">On Dec 21, 2017, at 6:01 PM, Hooman Mehr 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; line-break: after-white-space;"><div class="">The title is confusing, let me clarify by example:</div><div class=""><br class=""></div><div class="">We have this protocol with a mutating method:</div><div class=""><br class=""></div><div class=""><div class="" style="margin: 0px; font-stretch: normal; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(186, 45, 162); background-color: rgb(255, 255, 255);">protocol<span class=""><span class="Apple-converted-space"> </span>P {<span class="Apple-converted-space"> </span></span>mutating<span class=""><span class="Apple-converted-space"> </span></span>func<span class=""><span class="Apple-converted-space"> </span>f(</span>_<span class=""><span class="Apple-converted-space"> </span>x:<span class="Apple-converted-space"> </span></span><span class="" style="color: rgb(112, 61, 170);">Int</span><span class="">) -><span class="Apple-converted-space"> </span></span><span class="" style="color: rgb(112, 61, 170);">Int</span><span class=""><span class="Apple-converted-space"> </span>}</span></div></div><div class=""><br class=""></div><div class="">And a conforming class (which has to conform with a non-mutating method):</div><div class=""><br class=""></div><div class=""><div class="" style="margin: 0px; font-stretch: normal; font-size: 11px; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);"><span class="" style="color: rgb(186, 45, 162);">class</span><span class="Apple-converted-space"> </span>C:<span class="Apple-converted-space"> </span><span class="" style="color: rgb(79, 129, 135);">P</span><span class="Apple-converted-space"> </span>{<span class="Apple-converted-space"> </span><span class="" style="color: rgb(186, 45, 162);">func</span><span class="Apple-converted-space"> </span>f(<span class="" style="color: rgb(186, 45, 162);">_</span><span class="Apple-converted-space"> </span>x:<span class="Apple-converted-space"> </span><span class="" style="color: rgb(112, 61, 170);">Int</span>) -><span class="Apple-converted-space"> </span><span class="" style="color: rgb(112, 61, 170);">Int</span><span class="Apple-converted-space"> </span>{<span class="Apple-converted-space"> </span><span class="" style="color: rgb(186, 45, 162);">return</span><span class="Apple-converted-space"> </span>x } }</div></div><div class=""><br class=""></div><div class="">An instance of this class can be used with a let constant:</div><div class=""><br class=""></div><div class=""><div class="" style="margin: 0px; font-stretch: normal; font-size: 11px; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);"><span class="" style="color: rgb(186, 45, 162);">let</span><span class="Apple-converted-space"> </span>c =<span class="Apple-converted-space"> </span><span class="" style="color: rgb(79, 129, 135);">C</span>()</div><div class="" style="margin: 0px; font-stretch: normal; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(0, 132, 0); background-color: rgb(255, 255, 255);"><span class="" style="color: rgb(79, 129, 135);">c</span><span class="">.</span><span class="" style="color: rgb(49, 89, 93);">f</span><span class="">(</span><span class="" style="color: rgb(39, 42, 216);">1</span><span class="">)<span class="Apple-converted-space"> </span></span>// OK</div></div><div class=""> </div><div class="">If we make it an existential object conforming to P, the immutability of the method will be erased:</div><div class=""><br class=""></div><div class=""><div class="" style="margin: 0px; font-stretch: normal; font-size: 11px; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);"><span class="" style="color: rgb(186, 45, 162);">let</span><span class="Apple-converted-space"> </span>c:<span class="Apple-converted-space"> </span><span class="" style="color: rgb(112, 61, 170);">AnyObject</span><span class="Apple-converted-space"> </span>&<span class="Apple-converted-space"> </span><span class="" style="color: rgb(79, 129, 135);">P</span><span class="Apple-converted-space"> </span>=<span class="Apple-converted-space"> </span><span class="" style="color: rgb(79, 129, 135);">C</span>()</div><div class="" style="margin: 0px; font-stretch: normal; font-size: 11px; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);"><span class="" style="color: rgb(0, 132, 0);"><span class="" style="text-decoration: underline; color: rgb(79, 129, 135);">c</span><span class="">.f(</span><span class="" style="color: rgb(39, 42, 216);">1</span><span class="">)<span class="Apple-converted-space"> </span></span>//<span class="Apple-converted-space"> </span></span><font color="#ff2600" class="">Cannot use mutating member on immutable value: 'c' is a 'let' constant</font></div></div><div class=""><br class=""></div><div class="">A generic context has the same issue:</div><div class=""><br class=""></div><div class=""><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);"><span class="" style="font-family: Menlo; font-size: 11px; color: rgb(186, 45, 162);">func</span><font face="Menlo" class=""><span class="" style="font-size: 11px;"><span class="Apple-converted-space"> </span>f<T:<span class="Apple-converted-space"> </span></span></font><span class="" style="font-family: Menlo; font-size: 11px; color: rgb(112, 61, 170);">AnyObject</span><font face="Menlo" class=""><span class="" style="font-size: 11px;"><span class="Apple-converted-space"> </span>&<span class="Apple-converted-space"> </span></span></font><span class="" style="font-family: Menlo; font-size: 11px; color: rgb(79, 129, 135);">P</span><font face="Menlo" class=""><span class="" style="font-size: 11px;">>(</span></font><span class="" style="font-family: Menlo; font-size: 11px; color: rgb(186, 45, 162);">_</span><font face="Menlo" class=""><span class="" style="font-size: 11px;"><span class="Apple-converted-space"> </span>arg:<span class="Apple-converted-space"> </span></span></font><span class="" style="font-family: Menlo; font-size: 11px; color: rgb(79, 129, 135);">T</span><font face="Menlo" class=""><span class="" style="font-size: 11px;">)-><span class="Apple-converted-space"> </span></span></font><span class="" style="font-family: Menlo; font-size: 11px; color: rgb(112, 61, 170);">Int</span><font face="Menlo" class=""><span class="" style="font-size: 11px;"><span class="Apple-converted-space"> </span>{<span class="Apple-converted-space"> </span></span></font><span class="" style="font-family: Menlo; font-size: 11px; color: rgb(186, 45, 162);">return</span><span class="Apple-converted-space"> </span><span class="" style="font-family: Menlo; font-size: 11px; text-decoration: underline;">a</span><font face="Menlo" class=""><span class="" style="font-size: 11px;">rg.f(</span></font><span class="" style="font-family: Menlo; font-size: 11px; color: rgb(39, 42, 216);">1</span><font face="Menlo" class=""><span class="" style="font-size: 11px;">) } </span></font><span class="" style="font-family: Menlo; font-size: 11px; color: rgb(0, 132, 0);">// </span><font color="#ff2600" class=""><font face="Menlo" class=""><span class="" style="font-size: 11px;">Cannot use mutating member on immutable value: ‘arg' is a 'let' constant</span></font></font></div></div><div class=""><br class=""></div><div class=""><div class=""><b class="">My question: </b></div><div class=""><br class=""></div><div class="">Is it too much work to preserve method non-mutability in in these cases?</div></div><div class=""><br class=""></div><div class=""><div class="">The workaround I am using is this:</div><div class=""><br class=""></div><div class=""><div class="" style="margin: 0px; font-stretch: normal; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(0, 132, 0); background-color: rgb(255, 255, 255);"><span class="" style="color: rgb(186, 45, 162);">protocol</span><span class=""><span class="Apple-converted-space"> </span>Q:<span class="Apple-converted-space"> </span></span><span class="" style="color: rgb(112, 61, 170);">class, P<span class="Apple-converted-space"> </span></span><span class="">{<span class="Apple-converted-space"> </span></span><span class="" style="color: rgb(186, 45, 162);">func</span><span class=""><span class="Apple-converted-space"> </span>f(</span><span class="" style="color: rgb(186, 45, 162);">_</span><span class=""><span class="Apple-converted-space"> </span>x:<span class="Apple-converted-space"> </span></span><span class="" style="color: rgb(112, 61, 170);">Int</span><span class="">) -><span class="Apple-converted-space"> </span></span><span class="" style="color: rgb(112, 61, 170);">Int</span><span class=""><span class="Apple-converted-space"> </span>}<span class="Apple-converted-space"> </span></span>// 'Refine' it to be non-mutating.</div><div class="" style="margin: 0px; font-stretch: normal; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(186, 45, 162); background-color: rgb(255, 255, 255);">extension<span class=""><span class="Apple-converted-space"> </span></span><span class="" style="color: rgb(79, 129, 135);">C</span><span class="">:<span class="Apple-converted-space"> </span></span><span class="" style="color: rgb(79, 129, 135);">Q</span><span class=""><span class="Apple-converted-space"> </span>{}</span></div></div><div class="" style="margin: 0px; font-stretch: normal; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(186, 45, 162); background-color: rgb(255, 255, 255);"><span class=""><br class=""></span></div><div class="" style="margin: 0px; font-stretch: normal; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(186, 45, 162); background-color: rgb(255, 255, 255);"><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; color: rgb(0, 132, 0);">// Now these work:</div><div class="" style="margin: 0px; font-stretch: normal; line-height: normal;"><span class="" style="color: rgb(186, 45, 162);">let</span><span class="Apple-converted-space"> </span>c:<span class="Apple-converted-space"> </span><span class="" style="color: rgb(79, 129, 135);">Q</span><span class="Apple-converted-space"> </span>=<span class="Apple-converted-space"> </span><span class="" style="color: rgb(79, 129, 135);">C</span>()</div><div class="" style="margin: 0px; font-stretch: normal; line-height: normal; color: rgb(0, 132, 0);"><span class="" style="color: rgb(79, 129, 135);">c</span><span class="">.</span><span class="" style="color: rgb(49, 89, 93);">f</span><span class="">(</span><span class="" style="color: rgb(39, 42, 216);">1</span><span class="">)<span class="Apple-converted-space"> </span></span>// OK</div><div class="" style="margin: 0px; font-stretch: normal; line-height: normal;"><span class="" style="color: rgb(186, 45, 162);">func</span><span class="Apple-converted-space"> </span>f<T:<span class="Apple-converted-space"> </span><span class="" style="color: rgb(79, 129, 135);">Q</span>>(<span class="" style="color: rgb(186, 45, 162);">_</span><span class="Apple-converted-space"> </span>arg:<span class="Apple-converted-space"> </span><span class="" style="color: rgb(79, 129, 135);">T</span>)-><span class="Apple-converted-space"> </span><span class="" style="color: rgb(112, 61, 170);">Int</span><span class="Apple-converted-space"> </span>{<span class="Apple-converted-space"> </span><span class="" style="color: rgb(186, 45, 162);">return</span><span class="Apple-converted-space"> </span>arg.<span class="" style="color: rgb(49, 89, 93);">f</span>(<span class="" style="color: rgb(39, 42, 216);">1</span>) }<span class="Apple-converted-space"> </span><span class="" style="color: rgb(0, 132, 0);">// OK</span></div></div><div class=""><br class=""></div><div class="">This workaround creates a lot of duplication and is hard to maintain. It is not something that I do often, but when I do, it is pretty annoying. </div><div class=""><br class=""></div><div class=""><b class="">Supplemental questions:</b></div><div class=""><br class=""></div><div class="">Have you guys ever ran into this?</div></div><div class="">Is there already a bug tracking this? </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></div></div></div></blockquote></div></div></div></blockquote></div></div></blockquote></div><br class=""></body></html>