Reputation: 2875
enum Tree{
case Leaf(String)
case Node(Tree)
} //compiler not happy!!
enum Tree{
case Leaf(String)
case Node([Tree])
} //compiler is happy in (arguably) a more complex recursive scenario?
How can the Swift compiler work for the second (more complex) scenario and not the first?
Upvotes: 6
Views: 1204
Reputation: 1023
It is worth noting that Swift 2 beta 2 and further has indirect
keyword for recursive enum - that means
enum Tree<T> {
case Leaf(T)
indirect case Node(Tree)
}
is valid language construct that doesn't break pattern matching in Swift 2.
TL;DR of the decision: "[…] we decided that the right solution is to simply not support general, non-obvious recursion through enums, and require the programmer to mediate that explicitly with indirect."
Upvotes: 10
Reputation: 1817
Chris Lattner (designer of Swift) says on the Apple Developer forums that autoclosure
has emerged as a way to "box" expression value in a reference (e.g. working around limitations with recursive enums).
However, the following code (which works in Swift 1.1) does not work in Swift 1.2 that comes with Xcode Beta Version 6.3 (6D520o). The error message is "Attributes can only be applied to declarations, not types", however if this is intended, I don't know how to reconcile it with Lattner's statement about the behaviour he talks about in the previous quote as being "a useful thing, and we haven't removed it with Swift 1.2."
enum BinaryTree {
case Leaf(String)
case Node(@autoclosure () -> BinaryTree, @autoclosure () -> BinaryTree)
}
let l1 = BinaryTree.Leaf("A")
let l2 = BinaryTree.Leaf("B")
let l3 = BinaryTree.Leaf("C")
let l4 = BinaryTree.Leaf("D")
let n1 = BinaryTree.Node(l1, l2)
let n2 = BinaryTree.Node(l3, l4)
let t = BinaryTree.Node(n1, n2)
Upvotes: 1
Reputation: 122499
A value type (an enum) cannot contain itself as a direct member, since not matter how big a data structure is, it cannot contain itself. Apparently associated data of enum cases are considered direct members of the enum, so the associated data cannot be the type of the enum itself. (Actually, I wish that they would make recursive enums work; it would be so great for functional data structures.)
However, if you have a level of indirection, it is okay. For example, the associated data can be an object (instance of a class), and that class can have a member that is the enum. Since class types are reference types, it is just a pointer and does not directly contain the object (and thus the enum), so it is fine.
The answer to your question is: [Tree]
does not contain Tree
directly as a member. The fields of Array
are private, but we can generally infer that the storage for the elements of the array are not stored in the Array
struct directly, because this struct has a fixed size for a given Array<T>
, but the array can have unlimited number of elements.
Upvotes: 3