Recursive enums in Swift

In Swift, an enumeration (enum) is a type that groups related values together. Recursive enums take this concept further by allowing an enum to include instances of itself within its cases. This feature is particularly useful when modeling data that is nested or recursive in nature. By enabling a type to reference itself, recursive enums provide a straightforward and type-safe way to represent complex relationships, like those found in file systems or organizational structures.

To allow recursion within an enum, Swift uses the indirect keyword. This keyword instructs Swift to handle the enum's memory in a way that supports safe recursion, preventing issues that could arise from circular references.

Consider the task of modeling a file system where folders can contain both files and other folders. This hierarchical structure is a perfect example of where a recursive enum can be effectively used. Here’s how we can define such a system in Swift:

enum FileSystemItem {
    case file(name: String)
    case folder(name: String, items: [FileSystemItem])
    indirect case alias(name: String, to: FileSystemItem)
}

In this example, FileSystemItem has three cases. The file case represents a single file with a name. The folder case represents a directory that can contain an array of FileSystemItem instances, allowing it to hold files and other folders. The alias case, marked with indirect, represents a symbolic link or shortcut that references another FileSystemItem. The indirect keyword is necessary here because the alias case directly references another instance of the FileSystemItem enum.

Using this recursive enum, we can easily create a simple file system. Imagine we have two files that we want to place inside a "Documents" folder. Additionally, we want to create an alias to one of these files within a "Desktop" folder:

let imageFile = FileSystemItem.file(name: "photo.png")
let textFile = FileSystemItem.file(name: "notes.txt")

let documentsFolder = FileSystemItem.folder(
    name: "Documents",
    items: [imageFile, textFile]
)

let profileImageAlias = FileSystemItem.alias(name: "ProfileImage", to: imageFile)

let desktopFolder = FileSystemItem.folder(
    name: "Desktop",
    items: [documentsFolder, profileImageAlias]
)

In this setup, imageFile and textFile are individual files, while documentsFolder is a folder containing these files. The profileImageAlias is an alias pointing to the imageFile, and desktopFolder contains both the documentsFolder and the alias. This structure illustrates how recursive enums can be used to create a hierarchical, yet easily manageable file system with the added flexibility of aliases.

Integrating SwiftUI into UIKit Apps by Natalia Panferova book coverIntegrating SwiftUI into UIKit Apps by Natalia Panferova book cover

Enhance older apps with SwiftUI!$45

A detailed guide on gradually adopting SwiftUI in UIKit projects

Integrating SwiftUI into UIKit Appsby Natalia Panferova

  • Upgrade your apps with new features like Swift Charts and Widgets
  • Support older iOS versions with effective backward-compatible strategies
  • Seamlessly bridge state and data between UIKit and SwiftUI using the latest APIs

Enhance older apps with SwiftUI!

A detailed guide on gradually adopting SwiftUI in UIKit projects

Integrating SwiftUI into UIKit Apps by Natalia Panferova book coverIntegrating SwiftUI into UIKit Apps by Natalia Panferova book cover

Integrating SwiftUI
into UIKit Apps

by Natalia Panferova

$45

To count the total number of items (files, folders, and aliases) in a folder, including those in subfolders and through aliases, we can write a recursive function:

func countItems(in item: FileSystemItem) -> Int {
    switch item {
    case .file:
        return 1
    case .folder(_, let items):
        return items.map(countItems).reduce(0, +)
    case .alias(_, let to):
        return countItems(in: to)
    }
}

let totalItems = countItems(in: desktopFolder)
print("Total items: \(totalItems)")

This function works by returning 1 for each file, recursively counting the items within each folder, and handling aliases by counting the items they reference. The reduce() function sums these counts to provide the total number of items, regardless of how deeply nested they are or how many aliases exist.

The use of the indirect keyword in the alias case is essential for enabling recursion in enums like this. The indirect keyword is required when a case directly references the enum itself, as seen in the alias case (alias(name: String, to: FileSystemItem)). However, when the reference is through a collection type, such as an array in items: [FileSystemItem], the compiler does not require indirect because the array itself introduces the necessary level of indirection.

Recursive enums are a powerful feature in Swift that allow us to model complex, hierarchical data structures like file systems with clarity and precision. By understanding how and when to use the indirect keyword, we can leverage recursive enums to create robust and maintainable models for a variety of applications.


If you're an experienced Swift developer looking to learn advanced techniques, check out my latest book Swift Gems. It’s packed with tips and tricks focused solely on the Swift language and Swift Standard Library. From optimizing collections and handling strings to mastering asynchronous programming and debugging, "Swift Gems" provides practical advice that will elevate your Swift development skills to the next level. Grab your copy and let's explore these advanced techniques together.

Swift Gems by Natalia Panferova book coverSwift Gems by Natalia Panferova book cover

Level up your Swift skills!$35

100+ tips to take your Swift code to the next level

Swift Gemsby Natalia Panferova

  • Advanced Swift techniques for experienced developers bypassing basic tutorials
  • Curated, actionable tips ready for immediate integration into any Swift project
  • Strategies to improve code quality, structure, and performance across all platforms

Level up your Swift skills!

100+ tips to take your Swift code to the next level

Swift Gems by Natalia Panferova book coverSwift Gems by Natalia Panferova book cover

Swift Gems

by Natalia Panferova

$35