Boom Boom Enum

To quote a fairly awful movie: “We were so, so wrong.” — me

Remember I said you couldn’t use Swift value types for a linked list? The real reason is because you can’t have references to other value instances, just copies (thus making bi-directional linked lists a recursion nightmare), but the compiler error was “a value type can’t refer to itself”.

Turns out, one Swift value type can refer to itself: enumerations. By adding the indirect keyword, you can use Swift enums to, for example, represent a binary tree structure:

indirect enum Tree {
	 case node(Int, left: Tree?, right: Tree?)
}

And it works! But is it a good idea? Hell, no!

Why not? Because accessing the “properties” of your data structure is a pain in the ass:

switch node {
case let .node (data, left, right):
	// Do something with data, left, and right
}

As far as I know, you need an otherwise extraneous switch statement, a case statement, and an extra set of local variables just to access the values. (Whereas for a class all you need is dot syntax.) And you need to do that everywhere you want to access them, every method.

And the compiler will complain if you don’t use all of the enumeration values, so you have to remember to use _ for those:

switch node {
case let .node (_, left, _):
	// Do something with left
}

I tried writing a full tree traversal implementation in Swift with enum-based trees and it was an unholy mess that I would not repeat.

Learn from me. Don’t use cool language features at the expense of maintainability.

One comment

  1. Holmes Futrell

    I’m not sure if this approach will work for your application, but check out this WWDC talk. Fast forward to 30 minutes in (“A value type can contain a reference”):

    https://developer.apple.com/videos/play/wwdc2015/414/

    One approach is to have an internal representation of your object using a Class, but which you wrap with a struct in order to have value semantics externally. In your struct’s mutators you query the runtime to see if there are multiple references to the struct (isUniquelyReferencedNonObjC / isKnownUniquelyReferenced), and if so you create a deep copy of the internal class instance prior to mutating the data. Apple uses this pattern all over the place to create value types from things that are actually implemented by classes under the hood.

    You might also take a look at Swift pointer types.