Hello fellow evolutionists,

I’m not sure this list is the best place to talk about this, so please redirect 
me if it should be discussed elsewhere.

While trying to implement algebraic data types in Swift, I stumble upon an 
interesting problem. Let’s consider the following example:

protocol Term {}

struct Zero: Term {}
struct Succ: Term {
    let pred: Term
}


var term: Term = Zero()
for _ in 0 ..< 20000 {
    term = Succ(pred: term)
}

This code will take forever to execute (about 1 minute on my mbp late 2013), 
whereas if I replace the structures with reference types it will finish almost 
instantly, which is what one would expect from such a simple data structure. 
Most likely, the problem lays in the fact that a deep copy is produced every 
time a new level of recursion is created. However, I guess this case could be 
detected by the compiler, as the `term` variable passed as parameter is 
immediately affected to the rvalue of the expression using it.

An even more powerful approach would be to keep track of the reference on the 
original `term` value under the hood, and update it if necessary in a 
copy-on-write fashion. As I understand it, this would enable this code to be 
efficiently executed as well:

protocol Term {}

struct Leaf: Term {}
struct Tree: Term {
    let left: Term
    let right: Term
}

var tree: Term = Leaf()
for _ in 0 ..< 20000 {
    tree = Tree(left: tree, right: tree)
}

Interestingly, while enumerations are value types, indirect enumerations don’t 
suffer the performance issue of the above examples. Note however that the issue 
will reappear if the enum isn’t marked `indirect`.

protocol Term {}

indirect enum Nat: Term {
    case zero
    case succ(Term)
}

var term = Nat.zero
for _ in 0 ..< 20000 {
    term = .succ(term)
}

Thanks,
Dimitri Racordon

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to