<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body dir="auto"><div>Thanks. It's a shame this isn't being addressed. I find myself always considering whether things are value-type or reference-type when writing generic code, avoiding assignments to self for this reason, and feel bad adding mutating methods to protocols knowing that it will make the protocol almost unusable for classes. Maybe I'm the exception?</div><div><br></div><div>I think that if we had an AnyValue protocol, a Copyable protocol could provide value-types a default implementation which returns self, and this could be used when copying is needed. It would at least be better than restricting protocols to AnyValue. It seems it would work for your ‘removing’ example, even if it doesn't solve the underlying problem.</div><div><br></div><div><div>From James F</div></div><div><br>On 4 May 2016, at 04:02, Jordan Rose <<a href="mailto:jordan_rose@apple.com">jordan_rose@apple.com</a>> wrote:<br><br></div><blockquote type="cite"><div><meta http-equiv="Content-Type" content="text/html charset=cp932"><div class="">Dave and I have pondered this before, and considered that one possible (drastic) solution is to ban classes from implementing protocols with mutating members, on the grounds that it’s very hard to write an algorithm that’s correct for both.</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class="">func removing(_ element: Element) -> Self {</div><div class=""> var result = self<i class=""> // not necessarily a copy…</i></div><div class=""> result.remove(element)</div><div class=""> return result<i class=""> // not necessarily an independent value</i></div><div class="">}</div></blockquote><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class="">func zapBadElements<C: RangeReplaceableCollection where C.Generator.Element == Int>(_ nums: inout C) {</div><div class=""> <i class="">// requires inout on ‘nums’ even when it’s a class</i></div><div class=""> for i in nums.indices {</div><div class=""> if nums[i] < 0 {</div><div class=""> nums.removeAtIndex(i)</div><div class=""> }</div><div class=""> }</div><div class=""> <i class="">// …because of this.</i></div><div class=""><i class=""> </i>if nums.lazy.filter { $0 == 0 }.count > 5 {</div><div class=""> nums = C()</div><div class=""> }</div><div class="">}</div><div class=""><br class=""></div><div class="">var refCollection: SharedArrayOfSomeKind<Int> = …</div><div class=""><i class="">// either the variable ‘refCollection’ or the instance of ‘SharedArrayOfSomeKind’ might be mutated…or both!</i></div><div class="">zapBadElements(&refCollection)</div></blockquote><div class=""><br class=""></div>There are of course ways to safely use a protocol with mutating requirements with classes, namely if you <i class="">only</i> use them for mutation (i.e. they’re only called from ‘mutating’ members or on ‘inout’ parameters) and never rely on value copying (no assignment, no returning). Most simple wrappers around mutating members would fall into this category.<div class=""><br class=""></div><div class="">We didn’t really develop the idea very far yet because there’s been more pressing things to worry about. I’m bringing it up here because it’s an important idea that shouldn’t get lost.<br class=""><div class=""><div class=""><br class=""></div><div class="">---<br class=""><div class=""><br class=""></div><div class="">In lieu of this, I and a few others brought up the “incorrect” behavior of reassigning ‘self’ in a protocol extension when the model type is a class, and got shot down. I don’t have those discussions on hand at the moment, but I remember we deliberately decided to leave protocol extensions the way they were, allowing them to reassign class references. I think it’s because it means things like zapBadElements are more likely to work correctly^W as expected―if you don’t have any other references at the time you do the mutation, it can work. But yeah, I’m uncomfortable with the situation we’re in right now.</div><div class=""><br class=""></div><div class="">Jordan</div><div class=""><br class=""></div><br class=""><div><blockquote type="cite" class=""><div class="">On May 3, 2016, at 13:09, James Froggatt 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 dir="auto" class=""><div class="">Thanks for the response, I agree this is currently the best solution. Unfortunately, it's not just as simple as just implementing each method, since without being able to call super, I have to fully reimplement the original behaviour, which at best seems like bad practice, and would break in future versions of Swift, and at worst could lead to hard-to-detect bugs right now.</div><div class=""><br class=""></div><div class="">To recap for anyone reading, protocol extensions currently apply mutating methods unmodified to reference types, as I found trying to make a reference-type collection. This results in the compiler disallowing ‘let’ when calling these functions, and allows methods to reassign the reference ‘self’ to a new object. The best solution is to manually implement each method, removing the mutating modifier<span style="background-color: rgba(255, 255, 255, 0);" class="">, yet this workaround doesn't extend to generic code.</span></div><div class=""><br class=""></div><div class=""><span style="background-color: rgba(255, 255, 255, 0);" class="">To fix this behaviour, we would need to distinguish between ‘true’ mutating functions, which reassign self, and ‘partially’ mutating functions, for use in generics and protocol extensions, which can reassign properties only.</span></div><div class=""><div class=""><span style="background-color: rgba(255, 255, 255, 0);" class="">Is there any support for making this change? Or are there any simpler solutions?</span></div><div class=""><span style="background-color: rgba(255, 255, 255, 0);" class=""><br class=""></span></div><div class=""><span style="background-color: rgba(255, 255, 255, 0);" class="">I did submit a bug report, but I'm pretty sure a decent fix is not possible without some evolution of the language regarding the mutating keyword, so I'm trying to bring this up here in hope of us getting an actual solution. I've changed the title to what I hope is something that better reflects the problem; this thread was originally titled ‘[</span>swift-evolution] [Bug?] Reference types and mutating methods’.</div><div class=""><span style="background-color: rgba(255, 255, 255, 0);" class=""><br class=""></span></div><div class=""><span style="background-color: rgba(255, 255, 255, 0);" class=""><br class=""></span></div></div><div class="">PS: I have noticed another side-effect of calling mutating functions on my reference-type collection: it seems to trigger didChange on properties, even when, upon comparing the new and old objects, the reference isn't being changed. I haven't done much experimentation with this behaviour; this may be an unexpected side-effect of an extension method assigning to self, but it feels like it could be undefined behaviour.</div><div class=""><br class="">From James F</div><div class=""><br class="">On 30 Apr 2016, at 16:38, T.J. Usiyan <<a href="mailto:griotspeak@gmail.com" class="">griotspeak@gmail.com</a>> wrote:<br class=""><br class=""></div><blockquote type="cite" class=""><div class=""><div dir="ltr" class="">The problem here seems to be with using the default implementation provided. If you override `append` in ObservedArray, the compiler allows it. That seems 'safe' but odd at first. I wouldn't *want* to implement every mutating method, but that is the current solution. I haven't puzzled out the reasoning behind this myself.<div class=""><br class=""></div><div class=""><br class=""><div class="">``` swift<br class=""><div class="">class ObservedArray<T> : ArrayLiteralConvertible {</div><div class=""> var value: [T]</div><div class=""> init(value: [T]) {</div><div class=""> self.value = value</div><div class=""> }</div><div class=""> required init() {</div><div class=""> self.value = []</div><div class=""> }</div><div class=""><br class=""></div><div class=""> required convenience init(arrayLiteral elements: T...) {</div><div class=""> self.init(elements)</div><div class=""> }</div><div class=""><br class=""></div><div class="">}</div><div class=""><br class=""></div><div class="">extension ObservedArray {</div><div class=""> typealias Index = Int</div><div class=""><br class=""></div><div class=""> var startIndex: Index {</div><div class=""> return value.startIndex</div><div class=""> }</div><div class=""><br class=""></div><div class=""> var endIndex: Index {</div><div class=""> return value.endIndex</div><div class=""> }</div><div class=""><br class=""></div><div class=""> subscript(position: Index) -> T {</div><div class=""> return value[position]</div><div class=""> }</div><div class=""><br class=""></div><div class="">}</div><div class=""><br class=""></div><div class="">extension ObservedArray : RangeReplaceableCollectionType {</div><div class=""> typealias Generator = IndexingGenerator<[T]></div><div class=""><br class=""></div><div class=""> func generate() -> Generator {</div><div class=""> return value.generate()</div><div class=""> }</div><div class="">}</div><div class=""><br class=""></div><div class="">extension ObservedArray {</div><div class=""> func replaceRange<C : CollectionType where C.Generator.Element == Generator.Element>(subRange: Range<Index>, with newElements: C) {</div><div class=""> value.replaceRange(subRange, with: newElements)</div><div class=""> }</div><div class=""><br class=""></div><div class=""> func append(newElement: T) { // <- adding this makes it work</div><div class=""> value.append(newElement)</div><div class=""> }</div><div class="">}</div><div class=""><br class=""></div><div class="">let array: ObservedArray<String> = []</div><div class="">array.append("1")</div><div class=""><br class=""></div><br class="">```</div><div class=""><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><br class=""></div></div></div></div><div class="gmail_extra"><br class=""><div class="gmail_quote">On Sat, Apr 30, 2016 at 7:52 AM, James Froggatt via swift-evolution <span dir="ltr" class=""><<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>></span> wrote:<br class=""><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">I don't believe this has been addressed, please correct me if I'm wrong.<br class="">
<br class="">
--My Situation--<br class="">
I've recently been working on an observable collection type. Because each stores ‘subscriptions’ to changes that occur, it made sense to me that this should be a reference type, so subscriptions can't be copied with the values themselves.<br class="">
<br class="">
I have made this class conform to RangeReplaceableCollectionType, providing it with all the standard collection functions. I do the following:<br class="">
<br class="">
let array: ObservedArray<String> = []<br class="">
array.append("1") //Error: Cannot use mutating member on immutable value: ‘array’ is a ‘let’ constant<br class="">
<br class="">
I have to make the reference immutable just to use my new collection type? This is a bit of a deal-breaker.<br class="">
<br class="">
--The Problem--<br class="">
Mutating methods allow ‘self’ to be reassigned, which is just another way to mutate a value type. However, reassigning ‘self’ has a special meaning to reference types, which is presumably the reason they are disallowed in classes.<br class="">
<br class="">
However, classes can conform to protocols with mutating methods, leading to the compiler disallowing calls to mutating methods for ‘let’ values of type ‘protocol<MutatingProtocol, AnyObject>’, which can be an annoyance in generic code. In addition, classes can inherit mutating methods from protocol extensions, leading to the behaviour I describe above.<br class="">
<br class="">
Is this intentional behaviour? Am I going about this in the wrong way? Or is this really an omission in the language?<br class="">
_______________________________________________<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" rel="noreferrer" target="_blank" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class="">
</blockquote></div><br class=""></div>
</div></blockquote></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">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class=""></div></blockquote></div><br class=""></div></div></div></div></blockquote></body></html>