indirect enums and structs
SwiftStructEnumsSwift Problem Overview
To start off, I want to say that I'm aware there are many articles and questions within SO that refer to the indirect
keyword in Swift.
The most popular explanation for the usage of indirect
is to allow for recursive enums.
Rather than just knowing about what indirect
allows us to do, I would like to know how it allows us to use recursive enums.
Questions:
Is it because enums are value types and value types do not scale well if they are built in a recursive structure? Why?
Does indirect
modify the value type behaviour to behave more like a reference type?
The following two examples compile just fine. What is the difference?
indirect enum BinaryTree<T> {
case node(BinaryTree<T>, T, BinaryTree<T>)
case empty
}
enum BinaryTree<T> {
indirect case node(BinaryTree<T>, T, BinaryTree<T>)
case empty
}
Swift Solutions
Solution 1 - Swift
The indirect
keyword introduces a layer of indirection behind the scenes.
>You indicate that an enumeration case is recursive by writing indirect before it, which tells the compiler to insert the necessary layer of indirection.
From here
The important part of structs and enums is that they're a constant size. Allowing recursive structs or enums directly would violate this, as there would be an indeterminable number of recursions, hence making the size non constant and unpredictable. indirect
uses a constant size reference to refer to a constant size enum instance.
There's a different between the two code snippets you show.
-
The first piece of code makes
BinaryTree<T>
stored by a reference everywhere it's used. -
The second piece of code makes
BinaryTree<T>
stored by a reference only in the case ofnode
. I.e.BinaryTree<T>
generally has its value stored directly, except for this explicitlyindirect
node
case.
Solution 2 - Swift
Swift indirect enum
Since Swift v2.0
Swift Enum[About] is a value type[About], and we assign it the value is copied that is why the size of type should be calculated at compile time.
Problem with associated value
enum MyEnum { //Recursive enum <enum_name> is not marked
case case1(MyEnum) `indirect`
}
it is not possible to calculate the final size because of recursion
Indirect
says to compiler to store the associated value indirectly - by reference(instead of value)
indirect enum
- is stored as reference for all casesindirect case
- is stored as reference only for this case
Also indirect
is not applied for other value types(struct)