[swift-evolution] Proposal: Intermediate mutation qualifier for protocol functions on reference-types

Josh Avant mailinglists at iamjo.sh
Thu Dec 10 16:35:30 CST 2015


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.

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.

Consider this toy example:

```
import Foundation

protocol RandomDataTransformable {
    typealias TransformableType
    var data: [TransformableType] { get set }

    mutating func addRandomData()
}

extension RandomDataTransformable where TransformableType == Int {
    mutating func addRandomData() {
        let random = Int(arc4random_uniform(6) + 1)
        data.append(random)
    }
}


/////

// VALID
struct NumberSource_Struct : RandomDataTransformable {
    typealias TransformableType = Int
    var data: [Int] = []

    mutating func addData() {
        addRandomData()
    }
}


// VALID
class NumberSource_ClassDeclaration: NSObject, RandomDataTransformable {
    typealias TransformableType = Int
    var data: [Int] = []
}

var numberSource = NumberSource_ClassDeclaration()
numberSource.addRandomData()


// INVALID
class NumberSource_ClassImplementation: NSObject, RandomDataTransformable {
    typealias TransformableType = Int
    var data: [Int] = []

    func addData() {
        self.addRandomData() // Compiler Error: Cannot use mutating member
on immutable value: 'self' is immutable
    }
}
```

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`.

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).

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.

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.

Thoughts, feedback on this?
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151210/eea06029/attachment.html>


More information about the swift-evolution mailing list