[swift-evolution] [Oversight] Reference types allow mutating methods through generics

Joe Groff jgroff at apple.com
Wed May 4 13:30:32 CDT 2016


> On May 3, 2016, at 8:02 PM, Jordan Rose via swift-evolution <swift-evolution at swift.org> wrote:
> 
> 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.
> 
> func removing(_ element: Element) -> Self {
>   var result = self // not necessarily a copy…
>   result.remove(element)
>   return result // not necessarily an independent value
> }
> 
> func zapBadElements<C: RangeReplaceableCollection where C.Generator.Element == Int>(_ nums: inout C) {
>   // requires inout on ‘nums’  even when it’s a class
>   for i in nums.indices {
>     if nums[i] < 0 {
>       nums.removeAtIndex(i)
>     }
>   }
>   // …because of this.
>   if nums.lazy.filter { $0 == 0 }.count > 5 {
>     nums = C()
>   }
> }
> 
> var refCollection: SharedArrayOfSomeKind<Int> = …
> // either the variable ‘refCollection’ or the instance of ‘SharedArrayOfSomeKind’ might be mutated…or both!
> zapBadElements(&refCollection)
> 
> There are of course ways to safely use a protocol with mutating requirements with classes, namely if you only 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.
> 
> 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.

Something similar to the "classes can't conform to protocols with mutating requirements" restriction would fall out if we had a compiler-enforced notion of pure functions. A "pure" mutating method would only be allowed to mutate its `self` value; since a class reference's referenced instance is not part of the reference value, it wouldn't be possible for a class method that mutates the referenced instance to satisfy a pure mutating requirement.

-Joe


More information about the swift-evolution mailing list