Protocols & Mutability in Swift

βΈ»

Protocol Oriented Programming (POP) has become synonymous with the Swift programming language. Its an inherently better fit for Composition and generally leads to better architecture and code reuse. However its often difficult to deal with Mutability. 

Objective-C

In the Objective-C world, common practice (perhaps learned from Apple's SDK) was to create a Mutable subclass that provided read/write properties. This was extremely cumbersome and required a lot of maintenance. I think in Swift we can do better.

Example Problem

Lets say want a type to represent a control in our UI. This type should be immutable and has a single property defining its current state.

public protocol Control { 
    var state: State { get }
}

public final class Button: Control {
    public let state: State
}

Now lets define some API that will return an instance of our Control.

public func button(from json: JSONDictionary) -> Button {
    var control: Control = makeControl(from json: JSONDictionary)
    control.state = .default
    return control
}

The code above will throw an error at compile time, because state is read-only. Now we could obviously make it { get set } but that would allow our API consumers to modify the variable too.

Solution

Instead we can introduce a Mutable variant of our protocol. 

public protocol Control { 
    var state: State { get }
}

internal protocol MutableControl: Control {
    var state: State { get set }
}

public final class Button: MutableControl {
    public internal(set) var state: State
}

Notice that our Mutable variant is marked as Internal. This is the secret ingredient to making this work.

Now we can simply update our API to return our MutableControl without needing to expose internal features.

public func button(from json: JSONDictionary) -> Button {
    var control: MutableControl = makeControl(from json: JSONDictionary)
    control.state = .default
    return control
}

Summary

This is really nice feature and approach to solve immutability when using Swift Protocols. If you liked this post or want to get in touch, I'd love to hear from you.


If you liked this post or want to discuss more, leave a comment below or find me on Twitter