Skip to content →

Tag: mutation

Property Value Observing of Struct Types

The Swift Programming Language Guide has this to say about property value observing:

You have the option to define either or both of these observers on a property:

  • willSet is called just before the value is stored.

  • didSet is called immediately after the new value is stored.

Given that, how many times would you expect the following snippet to produce an output, “didSet dict”?

class SomeClass {
  var dict: [String: String]? {
    didSet {
      print("didSet dict")
    }
  }
}
let myClass = SomeClass()
myClass.dict = [:]
myClass.dict?["A"] = "alpha"
myClass.dict?.removeValueForKey("A")

What the documentation does not make clear is that for structures, which are value types, property observers are triggered both on assignment and on mutation; for classes, which are reference types, they are only triggered on assignment.

So for this example, where dict is a structure, didSet is called three times: once for the initial assignment, and twice for the two mutations. Good to know!

Leave a Comment

Protocols and Mutability

Apple writes in their Swift Programming Langauge Guide (v2.2):

If you define a protocol instance method requirement that is intended to mutate instances of any type that adopts the protocol, mark the method with the mutating keyword as part of the protocol’s definition. This enables structures and enumerations to adopt the protocol and satisfy that method requirement.

This makes sense in the context of their example protocol that defines a mutating method:

protocol Togglable {
  mutating func toggle()
}

But what of a protocol for which there is no foreknowledge or expectation of mutability, such as for a delegate that is notified when a parsing event occurs? Consider this source:

protocol XMLParserDelegate {
  func didParseXMLElement(element: XMLElement)
}

struct XMLDocument: XMLParserDelegate {

  var elements = [XMLElement]()

  func didParseXMLElement(element: XMLElement) {
    // Non-mutating code here
  }

  mutating func addElement(element: XMLElement) {
    elements.append(element)
  }
}

In this case, the XMLParserDelegate‘s didParseXMLElement(_:) does not have an expectation—as the aforementioned toggle() method does—that a conforming type will modify its own state. Thus it does not claim to be mutating.

As written above, the compiler does not complain. But as soon I declare didParseXMLElement(_:) as mutating, it does.

mutating func didParseXMLElement(element: XMLElement) {
  addElement(element)
}

Making the method mutating means it no longer conforms to the XMLParserDelegate method, where it is not declared such, and so Xcode informs: “Type ‘XMLDocument’ does not conform to protocol ‘XMLParserDelegate’.”

This restriction doesn’t seem reasonable. Why should a protocol be responsible for whether an adopting struct or enum is mutating? Is it not sufficient for that type to use the mutating specifier as it would be otherwise required to do?

One work-around is to declare the protocol method mutating—even though its name carries with it no suggestion of mutation—just in case an adopting type needs to perform a mutating operation. That doesn’t seem quite right, either.

So the best work-around appears be to make XMLDocument a class, thus eliminating the need for the mutating specifier in the first place:

class XMLDocument: XMLParserDelegate {

  var elements = [XMLElement]()

  func didParseXMLElement(element: XMLElement) {
    addElement(element)
  }

  func addElement(element: XMLElement) {
    elements.append(element)
  }
}

For a type that for all other intents and purposes need only be a structure, this is an unfortunate “promotion”.

Leave a Comment