<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="">Thank you Slava, it is a very insightful answer. <div class=""><br class=""></div><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 style="margin: 0px; font-stretch: normal; font-size: 11px; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class=""><span style="color: #ba2da2" class="">class</span> D: <span style="color: #4f8187" class="">C</span> { <span style="color: #ba2da2" class="">var</span> state = <span style="color: #272ad8" class="">0</span> }</div><div style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255); min-height: 14px;" class=""><br class=""></div><div 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);" class=""><span style="color: #ba2da2" class="">var</span><span style="color: #000000" class=""> d = </span><span style="color: #4f8187" class="">D</span><span style="color: #000000" class="">() </span>// Bad but common habit of declaring objects as var</div><div style="margin: 0px; font-stretch: normal; font-size: 11px; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class=""><span style="color: rgb(186, 45, 162);" class="">for</span> i <span style="color: rgb(186, 45, 162);" class="">in</span> <span style="color: rgb(39, 42, 216);" class="">1</span>...<span style="color: rgb(39, 42, 216);" class="">5</span> { <span style="color: rgb(79, 129, 135);" class="">d</span>.<span style="color: rgb(49, 89, 93);" class="">f</span>(i); <span style="color: rgb(79, 129, 135);" class="">d</span>.<span style="color: rgb(79, 129, 135);" class="">state</span> += <span style="color: rgb(39, 42, 216);" class="">1</span> }</div><div 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);" class=""><span style="color: #3e1e81" class="">print</span><span style="color: #000000" class="">(</span><span style="color: #4f8187" class="">d</span><span style="color: #000000" class="">.</span><span style="color: #4f8187" class="">state</span><span style="color: #000000" class="">) </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=""><br class=""></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 class=""><br class=""></div><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 class=""><br class=""></div><div class="">Hooman</div><div class=""><br class=""></div><div class=""><div><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=""><meta http-equiv="Content-Type" content="text/html; charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class="">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=""><meta http-equiv="Content-Type" content="text/html; charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><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 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);" class="">protocol<span style="" class=""> P { </span>mutating<span style="" class=""> </span>func<span style="" class=""> f(</span>_<span style="" class=""> x: </span><span style="color: #703daa" class="">Int</span><span style="" class="">) -> </span><span style="color: #703daa" class="">Int</span><span style="" class=""> }</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 style="margin: 0px; font-stretch: normal; font-size: 11px; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class=""><span style="color: #ba2da2" class="">class</span> C: <span style="color: #4f8187" class="">P</span> { <span style="color: #ba2da2" class="">func</span> f(<span style="color: #ba2da2" class="">_</span> x: <span style="color: #703daa" class="">Int</span>) -> <span style="color: #703daa" class="">Int</span> { <span style="color: #ba2da2" class="">return</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 style="margin: 0px; font-stretch: normal; font-size: 11px; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class=""><span style="color: #ba2da2" class="">let</span> c = <span style="color: #4f8187" class="">C</span>()</div><div 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);" class=""><span style="color: #4f8187" class="">c</span><span style="" class="">.</span><span style="color: #31595d" class="">f</span><span style="" class="">(</span><span style="color: #272ad8" class="">1</span><span style="" class="">) </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 style="margin: 0px; font-stretch: normal; font-size: 11px; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class=""><span style="color: #ba2da2" class="">let</span> c: <span style="color: #703daa" class="">AnyObject</span> & <span style="color: #4f8187" class="">P</span> = <span style="color: #4f8187" class="">C</span>()</div><div style="margin: 0px; font-stretch: normal; font-size: 11px; line-height: normal; font-family: Menlo; background-color: rgb(255, 255, 255);" class=""><span style="color: rgb(0, 132, 0);" class=""><span style="text-decoration: underline ; color: #4f8187" class="">c</span><span style="" class="">.f(</span><span style="color: #272ad8" class="">1</span><span style="" class="">) </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 style="margin: 0px; font-stretch: normal; line-height: normal; background-color: rgb(255, 255, 255);" class=""><span style="font-family: Menlo; font-size: 11px; color: rgb(186, 45, 162);" class="">func</span><font face="Menlo" class=""><span style="font-size: 11px;" class=""> f<T: </span></font><span style="font-family: Menlo; font-size: 11px; color: rgb(112, 61, 170);" class="">AnyObject</span><font face="Menlo" class=""><span style="font-size: 11px;" class=""> & </span></font><span style="font-family: Menlo; font-size: 11px; color: rgb(79, 129, 135);" class="">P</span><font face="Menlo" class=""><span style="font-size: 11px;" class="">>(</span></font><span style="font-family: Menlo; font-size: 11px; color: rgb(186, 45, 162);" class="">_</span><font face="Menlo" class=""><span style="font-size: 11px;" class=""> arg: </span></font><span style="font-family: Menlo; font-size: 11px; color: rgb(79, 129, 135);" class="">T</span><font face="Menlo" class=""><span style="font-size: 11px;" class="">)-> </span></font><span style="font-family: Menlo; font-size: 11px; color: rgb(112, 61, 170);" class="">Int</span><font face="Menlo" class=""><span style="font-size: 11px;" class=""> { </span></font><span style="font-family: Menlo; font-size: 11px; color: rgb(186, 45, 162);" class="">return</span> <span style="font-family: Menlo; font-size: 11px; text-decoration: underline;" class="">a</span><font face="Menlo" class=""><span style="font-size: 11px;" class="">rg.f(</span></font><span style="font-family: Menlo; font-size: 11px; color: rgb(39, 42, 216);" class="">1</span><font face="Menlo" class=""><span style="font-size: 11px;" class="">) } </span></font><span style="font-family: Menlo; font-size: 11px; color: rgb(0, 132, 0);" class="">// </span><font color="#ff2600" class=""><font face="Menlo" class=""><span style="font-size: 11px;" class="">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 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);" class=""><span style="color: #ba2da2" class="">protocol</span><span style="" class=""> Q: </span><span style="color: #703daa" class="">class, P </span><span style="" class="">{ </span><span style="color: #ba2da2" class="">func</span><span style="" class=""> f(</span><span style="color: #ba2da2" class="">_</span><span style="" class=""> x: </span><span style="color: #703daa" class="">Int</span><span style="" class="">) -> </span><span style="color: #703daa" class="">Int</span><span style="" class=""> } </span>// 'Refine' it to be non-mutating.</div><div 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);" class="">extension<span style="" class=""> </span><span style="color: #4f8187" class="">C</span><span style="" class="">: </span><span style="color: #4f8187" class="">Q</span><span style="" class=""> {}</span></div></div><div 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);" class=""><span style="" class=""><br class=""></span></div><div 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);" class=""><div style="margin: 0px; font-stretch: normal; line-height: normal; color: rgb(0, 132, 0);" class="">// Now these work:</div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class=""><span style="color: #ba2da2" class="">let</span> c: <span style="color: #4f8187" class="">Q</span> = <span style="color: #4f8187" class="">C</span>()</div><div style="margin: 0px; font-stretch: normal; line-height: normal; color: rgb(0, 132, 0);" class=""><span style="color: #4f8187" class="">c</span><span style="" class="">.</span><span style="color: #31595d" class="">f</span><span style="" class="">(</span><span style="color: #272ad8" class="">1</span><span style="" class="">) </span>// OK</div><div style="margin: 0px; font-stretch: normal; line-height: normal;" class=""><span style="color: #ba2da2" class="">func</span> f<T: <span style="color: #4f8187" class="">Q</span>>(<span style="color: #ba2da2" class="">_</span> arg: <span style="color: #4f8187" class="">T</span>)-> <span style="color: #703daa" class="">Int</span> { <span style="color: #ba2da2" class="">return</span> arg.<span style="color: #31595d" class="">f</span>(<span style="color: #272ad8" class="">1</span>) } <span style="color: #008400" class="">// 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 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><br class=""></div></blockquote></div><br class=""></div></div></div></blockquote></div><br class=""></div></body></html>