Thanks, Kevin!<div><br></div><div>Look forward to any other feedback!<br><br>On Thursday, December 10, 2015, Kevin Ballard via swift-evolution <<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><u></u>
<div><div>A couple of miscellaneous points:<br></div>
<div> </div>
<div>* This problem only occurs when the class inherits a default implementation of the method from a protocol extension. If the class declares the method itself, then it's no longer a mutating method and everything works fine.<br></div>
<div>* The problem exists because mutating functions are allowed to assign to self, but methods on class types cannot assign to self, they can only mutate the properties of self. This is why we cannot simply allow the call to the inherited mutating method, as that method may reassign self.<br></div>
<div>* Classes can still call the method, they just have to say something like<br></div>
<div> </div>
<div><span style="font-family:menlo,consolas,"courier new",monospace,sans-serif">var this = self</span><span style="font-family:menlo,consolas,"courier new",monospace,sans-serif"><br></span></div>
<div><span style="font-family:menlo,consolas,"courier new",monospace,sans-serif">this.callMutatingMethod()</span><span style="font-family:menlo,consolas,"courier new",monospace,sans-serif"><br></span></div>
<div> </div>
<div>Yeah it's a little awkward, but it's not really all that bad for an edge case like this.<br></div>
<div> </div>
<div>Another potential workaround requires more work on the protocol side but allows implementations to not care about the difference, which is to provide a non-mutating variant in an extension restricted by Self: AnyObject:<br></div>
<div> </div>
<div><span style="font-family:menlo,consolas,"courier new",monospace,sans-serif">protocol P {<br></span></div>
<div><span style="font-family:menlo,consolas,"courier new",monospace,sans-serif"> var count: Int { get set }<br></span></div>
<div><span style="font-family:menlo,consolas,"courier new",monospace,sans-serif"> mutating func foo() -> String<br></span></div>
<div><span style="font-family:menlo,consolas,"courier new",monospace,sans-serif">}<br></span></div>
<div> </div>
<div><span style="font-family:menlo,consolas,"courier new",monospace,sans-serif">extension P {<br></span></div>
<div><span style="font-family:menlo,consolas,"courier new",monospace,sans-serif"> mutating func foo() -> String {<br></span></div>
<div><span style="font-family:menlo,consolas,"courier new",monospace,sans-serif"> return _mutatingFoo(&self)<br></span></div>
<div><span style="font-family:menlo,consolas,"courier new",monospace,sans-serif"> }<br></span></div>
<div><span style="font-family:menlo,consolas,"courier new",monospace,sans-serif">}<br></span></div>
<div> </div>
<div><span style="font-family:menlo,consolas,"courier new",monospace,sans-serif">extension P where Self: AnyObject {<br></span></div>
<div><span style="font-family:menlo,consolas,"courier new",monospace,sans-serif"> func foo() -> String {<br></span></div>
<div><span style="font-family:menlo,consolas,"courier new",monospace,sans-serif"> var this = self<br></span></div>
<div><span style="font-family:menlo,consolas,"courier new",monospace,sans-serif"> return _mutatingFoo(&this)<br></span></div>
<div><span style="font-family:menlo,consolas,"courier new",monospace,sans-serif"> }<br></span></div>
<div><span style="font-family:menlo,consolas,"courier new",monospace,sans-serif">}<br></span></div>
<div> </div>
<div><span style="font-family:menlo,consolas,"courier new",monospace,sans-serif">private func _mutatingFoo<T: P>(inout value: T) -> String {<br></span></div>
<div><span style="font-family:menlo,consolas,"courier new",monospace,sans-serif"> value.count += 1<br></span></div>
<div><span style="font-family:menlo,consolas,"courier new",monospace,sans-serif"> return "foo"<br></span></div>
<div><span style="font-family:menlo,consolas,"courier new",monospace,sans-serif">}<br></span></div>
<div> </div>
<div>Ultimately, I think there's some value in this proposal, but I worry about adding a new keyword to handle an edge case like this when there's workarounds available. Assuming we do add this feature, I'd suggest using something like `mutating(ish)` instead of inventing a brand new keyword (there's precedent in `private(set)`).<br></div>
<div> </div>
<div>-Kevin Ballard</div>
<div> </div>
<div>On Thu, Dec 10, 2015, at 02:35 PM, Josh Avant via swift-evolution wrote:<br></div>
<blockquote type="cite"><div dir="ltr"><div>Currently, when a reference-type adopts a protocol with a function declared as `mutating`, the reference-type's implementation cannot call that function internally. This is because the compiler enforces an immutable `self` pointer value, and the `mutating` qualifier implies that the function implementation may mutate that `self` pointer value.<br></div>
<div> </div>
<div>However, there seems to be a number of fairly reasonable situations where a reference-type implementation of these `mutating` functions may only want to mutate properties owned by `self`, but not the actual `self` pointer value.<br></div>
<div> </div>
<div>Consider this toy example:<br></div>
<div> </div>
<div>```<br></div>
<div>import Foundation<br></div>
<div> </div>
<div>protocol RandomDataTransformable {<br></div>
<div> typealias TransformableType<br></div>
<div> var data: [TransformableType] { get set }<br></div>
<div> </div>
<div> mutating func addRandomData()<br></div>
<div>}<br></div>
<div> </div>
<div>extension RandomDataTransformable where TransformableType == Int {<br></div>
<div> mutating func addRandomData() {<br></div>
<div> let random = Int(arc4random_uniform(6) + 1)<br></div>
<div> data.append(random)<br></div>
<div> }<br></div>
<div>}<br></div>
<div> </div>
<div> </div>
<div>/////<br></div>
<div> </div>
<div>// VALID<br></div>
<div>struct NumberSource_Struct : RandomDataTransformable {<br></div>
<div> typealias TransformableType = Int<br></div>
<div> var data: [Int] = []<br></div>
<div> </div>
<div> mutating func addData() {<br></div>
<div> addRandomData()<br></div>
<div> }<br></div>
<div>}<br></div>
<div> </div>
<div> </div>
<div>// VALID<br></div>
<div>class NumberSource_ClassDeclaration: NSObject, RandomDataTransformable {<br></div>
<div> typealias TransformableType = Int<br></div>
<div> var data: [Int] = []<br></div>
<div>}<br></div>
<div> </div>
<div>var numberSource = NumberSource_ClassDeclaration()<br></div>
<div>numberSource.addRandomData()<br></div>
<div> </div>
<div> </div>
<div>// INVALID<br></div>
<div>class NumberSource_ClassImplementation: NSObject, RandomDataTransformable {<br></div>
<div> typealias TransformableType = Int<br></div>
<div> var data: [Int] = []<br></div>
<div> </div>
<div> func addData() {<br></div>
<div> self.addRandomData() // Compiler Error: Cannot use mutating member on immutable value: 'self' is immutable<br></div>
<div> }<br></div>
<div>}<br></div>
<div>```<br></div>
<div> </div>
<div>Even despite the fact that the default implementation for `addRandomData` does not mutate the `self` pointer value, reference-type implementations are unable to call that function internally, since it is marked as `mutating`.<br></div>
<div> </div>
<div>Perhaps confusingly, `addRandomData` may be called by externally, by objects which own instances of the reference-type (even though, again, it may not called internally by the implementation, itself).<br></div>
<div> </div>
<div>Currently, the only solution to allow reference-type implementations to call the sample `addRandomData` implementation internally is to qualify the whole `RandomDataTransformable` protocol as `class`. The downside here is that this takes an otherwise perfectly reference- and struct-compatible protocol + extension implementation and restricts it to only apply to classes, decreasing overall code reusability.<br></div>
<div> </div>
<div>My proposal would be to introduce an intermediate mutation qualifier that applies when protocols are adopted by reference-types. The qualifier would specify that the `self` pointer value itself may not be mutated, but `self`'s properties may be, as appropriate.<br></div>
<div> </div>
<div>Thoughts, feedback on this?<br></div>
</div>
<div><img style="min-height:1px!important;width:1px!important;border-top-width:0px!important;border-right-width:0px!important;border-bottom-width:0px!important;border-left-width:0px!important;margin-top:0px!important;margin-bottom:0px!important;margin-right:0px!important;margin-left:0px!important;padding-top:0px!important;padding-bottom:0px!important;padding-right:0px!important;padding-left:0px!important" border="0" height="1" width="1" alt="" src="https://www.fastmailusercontent.com/proxy/b3b692329332b943295dfc8454c0e94db5a907328abf7ffdb39b752b54b97fc1/8647470737a3f2f25723030323431303e23647e23756e64676279646e2e65647f27766f2f60756e6f35707e6d3148765176786c673171614a7d2236454230345272776e495e40563859697437636b4863644a5d4475397d223243774f6453796949736653347741767475736a48466746666a447c43607e634237716936726f43424d4c6d67507a7d686f635878564460337d22364b60753676583c6c46494d2236473c4c663139635d4a714546545e674e61653233724c6a54305f605d2232497a6a764649597c454a695543707565546d687f42384b6b6a6f426053486f425c696e434253576b6c6847517159315f464f613272547232675b6f4774613a4331464b67685a76726f474466615d23344d23344/open"><br></div>
<div><u>_______________________________________________</u><br></div>
<div>swift-evolution mailing list<br></div>
<div><a href="javascript:_e(%7B%7D,'cvml','swift-evolution@swift.org');" target="_blank">swift-evolution@swift.org</a><br></div>
<div><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br></div>
</blockquote><div> </div>
<img src="https://u2002410.ct.sendgrid.net/wf/open?upn=UqrBeBSFFZ3qCW2UhjXSFiQVUl3B3t-2Bn3RK9F3k22XngI33MPlIGaYAqG-2BZl0C02P7ydD3ZilX0-2Fz65yf096uIncFm36rZs2F-2Bc-2FjfrvarUgkYU9Q2P78swEkt9ToUvCJ-2FmXoixaOQ7YMaXXDUaHR0WkkpLVEMMuJ49f2HnDuUFNDiYhBqbTQacaW7XD60T0-2FrGrFfqpHA9fnR4QNGCLqbClLLYVV0EFpShu8Y5oCI4-3D" alt="" width="1" height="1" border="0" style="min-height:1px!important;width:1px!important;border-width:0!important;margin-top:0!important;margin-bottom:0!important;margin-right:0!important;margin-left:0!important;padding-top:0!important;padding-bottom:0!important;padding-right:0!important;padding-left:0!important">
</div>
</blockquote></div>