So I noticed that when a reference type is captured by a closure (even if that closure is non-escaping), Swift inserts retain/release calls around it:
public class Object { var count = 0 }
@inline(never)
func execute<T>(closure: () -> T) -> T {
closure()
}
func compare(reference: Object, count: Int) -> Bool {
// retain Object
execute { reference.count == count }
// release Object
}
This retain/release is eliminated if Swift is allowed to inline the closure:
//@inline(never)
func execute<T>(closure: () -> T) -> T {
closure()
}
func compare(reference: Object, count: Int) -> Bool {
// no retain of Object
execute { reference.count == count }
// no release of Object
}
or if the closure is explicitly eliminated entirely:
// no retain/release here:
func compare(reference: Object, count: Int) -> Bool {
reference.count == count
}
Even though I would assume Swift should be able to safely optimize away the retain/release calls in both scenarios, inlining or not, the behavior here suggests to me that Swift is assuming that the closure might do things that could cause Object
to be released, and inserts a retain/release call to protect against that. What are some of those things?