Cool Swift Tricks 1: Mirror, Mirror

This is the first of four posts about random little Swift tips and tricks for you to amaze your friends and confound your enemies. All of these came up in my real code recently, and they really did surprise one or more of my co-workers. The Swift language has a lot of cool features hidden away in its nooks and crannies, but most real developers are too busy getting real work done to keep up with all of them; so every once in a while I've submitted a pull request that made someone say, "Hey, I didn't know about that!" If you already knew about these features, you can feel smug, and if you didn't, now you do, so you can feel smug anyway.


We had a bunch of value types in our app, basically just collections of properties. While debugging, these would all print out nicely in the LLDB console as a list of their properties along with their values — except for one. After a while, I realized what the problem was: the ones that printed out nicely were structs, but the problematic one was a class.

For example:

struct Person {
    let name: String
    let age: Int
    let pet: Pet
}

class Pet {
    let name: String
    let license: Int
    init(name:String, license:Int) {
        self.name = name; self.license = license
    }
}

let pet = Pet(name: "Speedy", license: 123)
let person = Person(name: "Lear", age: 80, pet: pet)

Now in LLDB we try to examine person, and here's what we get:

(lldb) po person
▿ Person
  - name : "Lear"
  - age : 80
  ▿ pet : <Pet: 0x600001a22040>

So LLDB is happy to give me a property-based picture of a Person, but not of a Pet. I have no idea why that is. Now, you could say, "Call dump"; but there's no time for that, because I have lots of these Pet objects popping up all the time. You could also say, "Write a description property for Pet"; but there's no time for that either, because in real life this class has a lot of properties — and besides, if we add or remove a property, I have to remember to rewrite my description implementation.

What I do have time for is to whip up a protocol that uses Mirror introspection to report on a type's properties in general, without my having to specify what they are:

protocol Introspectable: CustomDebugStringConvertible {}
extension Introspectable {
    var debugDescription: String {
        var output = ""
        for child in Mirror(reflecting: self).children {
            output += (child.label ?? "") + ": " + String(describing: child.value) + "n"
        }
        return output
    }
}

Now all I have to do is declare that Pet conforms to Introspectable, thereby injecting my definition of debugDescription into it. The po command in LLDB uses debugDescription if it exists, so now here's what happens in LLDB:

(lldb) po person
▿ Person
  - name : "Lear"
  - age : 80
  ▿ pet : name: Speedy
license: 123

It's not elegant, and the formatting isn't perfect, but at least I see the Pet properties and their values so I can get on with debugging the app. Even better, it surprised a colleague, who didn't know that Mirror could be put to such a practical use.

Check out part 2 of Cool Swift Tricks: No Escape