Swift uses ARC (automatic reference counting), an automatic memory management scheme in which cycles must be broken by the programmer. This is usually accomplished with unowned
or more commonly with weak
. These modifiers can be applied to closure captures or property storage.
Swift protocols are a powerful abstraction mechanism; generics and large chunks of the standard library are built on them. Swift also treats value types as first-class citizens, allowing enums and structs to conform to protocols. The choice of value type vs reference type can be made on the basis of the problem you are modeling, mutability, and sharing.
These two worlds collide when it comes to weak. It is not currently possible to declare a weak-any property, nor weakly capture a non-class type in a closure. This is illegal:
class Fizz {
// error: 'weak' must not be applied to non-class-bound 'Any'
weak var delegate: Any?
}
The same applies to protocols and generic types:
class Fuzz<T> {
// error: 'weak' must not be applied to non-class-bound 'T'
weak var fuzzyWuzzle: T?
}
This presents a problem for a library or API designer: How can I make it easy to avoid reference cycles for clients using a reference type without prohibiting the use of value types for all clients? It can also be problematic to use escaping closures in an entirely private implementation, which is an unwelcome leaky abstraction.
My pitch is very simple: Allow declaration of weak Any values. If the underlying value is a value type the weak declaration has no effect. If it is a reference type the capture is weak. This allows certain code patterns to be fully generic with respect to value vs reference types.
Swift must already deal with reference types held in an Any value, dynamically determining whether ARC operations are required. It is my hope that handling weak would not impose any significant additional costs but that may not be the case. In any event only properties or captures declared as weak Any would pay the price.
The generic case is more interesting. For internal implementations the compiler knows the specializations and could presumably discard the weak qualifier for value types at compile time. Across module boundaries or for non-specialized code I'm less sure of the fallout.
Are there fatal flaws I haven't considered? Does this seem like a reasonable thing to do? Have you ever run across cases where this would be useful in your own code? If so how did you work around it?