Tangential to the main discussion points of this thread, but there is one application of private protocol members I've wished for in practice that the language doesn't currently have an excellent solution for: default implementations of protocol requirements.
Take a hypothetical example:
/// Conforming types keep a tally of some type of event.
protocol Tallying {
var totalTally: Int { get }
/// Records that the associated event has occurred by incrementing `totalTally`.
mutating func tally()
}
In this case, the implementation of tally() is trivial and uninteresting, so it'd be great to give it a default implementation:
extension Tallying {
mutating func tally() {
totalTally += 1 // ❌ error: left side of mutating operator isn't mutable: 'totalTally' is a get-only property
}
}
Ideally, it'd be great to be able to express
protocol Tallying {
var totalTally: Int { get private(set) }
}
but this isn't currently allowed. At the moment, you have to:
- Declare
totalTally's setter as public, - Keep
totalTallyas-is, but give it a default implementation in terms of, e.g., a property like_totalTally(public, but underscored to discourage direct use), or - Turn
Tallyinginto a class with a private setter fortotalTallyand an implementation oftally(), from which other classes can inherit
(1) opens the door for accidental misuse of the property; (2) makes accidental misuse less likely, but makes conforming to the protocol convoluted (especially if the protocol has a long list of requirements); (3) is only applicable for classes (which don't already need to inherit from a different existing type).
(I completely agree with Swift's take that a protocol should define the public, semantic interface of a type — but to some extent, you can argue that "this property must be internally mutable since the semantics of the protocol require it to change" could be included in that approach.)