Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reference cycles with value types?

Reference cycles in Swift occur when properties of reference types have strong ownership of each other (or with closures).

Is there, however, a possibility of having reference cycles with value types only?


I tried this in playground without succes (Error: Recursive value type 'A' is not allowed).

struct A {
  var otherA: A? = nil
  init() {
    otherA = A()
  }
}
like image 737
Christoffer Dures Avatar asked Jul 04 '16 19:07

Christoffer Dures


People also ask

What are reference cycles?

A reference cycle simply means one or more objects referencing each other, such that if you drew it out on paper with arrows representing the dependencies you would see a cycle.

What is a strong reference cycle?

A strong reference cycle is when two instances of classes reference each other without the proper safeties ( weak / unowned ) hence preventing the garbage collector from disposing of them once all the variables I created stopped referencing those objects.

How do you resolve a strong reference cycle in closures?

Resolving Strong Reference Cycles for Closures. You resolve a strong reference cycle between a closure and a class instance by defining a capture list as part of the closure's definition. A capture list defines the rules to use when capturing one or more reference types within the closure's body.

How can you avoid strong reference cycles in a closure?

A strong reference cycle happens when 2 instances keep a strong reference to each other. You can accidentally create such a cyclic reference, for example when working with 2-way “links” between objects, or with closures. You can break the cycle by marking a reference as weak, or by setting one of the references to nil.


2 Answers

A reference cycle (or retain cycle) is so named because it indicates a cycle in the object graph:

retain cycle

Each arrow indicates one object retaining another (a strong reference). Unless the cycle is broken, the memory for these objects will never be freed.

When capturing and storing value types (structs and enums), there is no such thing as a reference. Values are copied, rather than referenced, although values can hold references to objects.

In other words, values can have outgoing arrows in the object graph, but no incoming arrows. That means they can't participate in a cycle.

like image 110
jtbandes Avatar answered Sep 27 '22 19:09

jtbandes


As the compiler told you, what you're trying to do is illegal. Exactly because this is a value type, there's no coherent, efficient way to implement what you're describing. If a type needs to refer to itself (e.g., it has a property that is of the same type as itself), use a class, not a struct.

Alternatively, you can use an enum, but only in a special, limited way: an enum case's associated value can be an instance of that enum, provided the case (or the entire enum) is marked indirect:

enum Node {
    case None(Int)
    indirect case left(Int, Node)
    indirect case right(Int, Node)
    indirect case both(Int, Node, Node)
}
like image 23
matt Avatar answered Sep 27 '22 19:09

matt