Swift enumerations: love & hate
Sun, 05 Mar 2017 11:17:44 +0000
Enumerations are one of those constructs that differ a lot across different programming languages. While in C they were just a series of named integer constants, in Java they are almost full-blown classes, and in fact, they are awesome for implementing singletons.

Swift doesn't follow the generalist route of Java, and instead it uses enums to enumerate things, that's it. But making them simple to understand doesn't mean that they need to be just ints, like in C. In fact, enums in Swift can hold associated values. For instance,

enum SerializationError: Error {
    case missing(String)
    case invalid(String, Any)
}

// in some deserialization code
    guard let vertexData = json["vertices"] as? [Float] else {
        throw SerializationError.missing("vertices")
    }

// handling errors with different associated values

switch serializationError {
case .missing(let what):
    print("\(what) is missing")
case .invalid(let what, let someObject):
    print("\(what) is invalid: \(someObject)"
}

So enums in Swift are awesome to deal with values in a type-safe way, and I tend to use them a lot.

However, there's a dark side: the implementation. In Swift relative short lifetime I have already 2 nasty bugs that have made me waste many hours. You never expect the language to be wrong, so you try to find what's wrong with your code first, until you realize it's not your code...

The first bug I found almost a couple of years ago had to do with variable accessors: Accessor bug in release. The values of an array of enums would appear as 0 values in all cases, but only in Release mode! Super obscure and really hard to debug. I found that in Swift 1.3 and it wasn't fixed until Swift 2.1.

The second bug I just found yesterday. I was checking for leaks in some Metal code. I found many leaks everywhere, and I started getting paranoid, because the Metal code is full of UnsafeRawPointers, memcopies, Metal buffers, Metal textures, ... After a 6-hour debugging session I just reduced it all to this small repro case: Swift 3 enums leak memory when the class also contains an array. It's very strange, because if I replace the enum by an int, then there's no leak. So I assumed labeling the enum @objc (same workaround as the first bug) would fix the problem, but it doesn't. And the thing that leaks is the array when it gets copied after appending an element to it. Very strange and still no solution for it.

The question now is: should I trust enums again? My code looks nicer with them than if I changed everything to ints, definitely... I guess I should trust Apple or Swift maintainers to do something about it. For the time being, I reported it to Apple. And I guess I won't change my code just right now...

As the title says, it's a love & hate relation between me and Swift enums. 😍😡

 
Newer|Older

Previous year

Next year