Sam
Sam

Reputation: 2875

Strange behaviour for recursive enum in Swift (Beta 7)

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

Answers (3)

mpolednik
mpolednik

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

Aky
Aky

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

newacct
newacct

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

Related Questions