test code:
class Person {
deinit {
print("Person deinit")
}
}
class Student {
deinit {
print("Student deinit")
}
}
func run() {
let person = Person()
var student = Student()
print("run end")
}
run()
output result:

Encountered a problem, in release mode, let variables should be released before the end of "run end" like var variables, why are let variables released after "run end"?
Is there any reason here?
What optimization settings was this built with?
tera
4
Are you suggesting there is a bug or are you just curious why it is so? AFAIK nothing in the language specifies guarantees in this behaviour, so even two vars or two lets can behave differently. IIRC there was a (pre?) pitch thread here a couple of months ago that proposed to make variable lifetime more deterministic, until that - it is what it is.
1 Like
While that's true I am still curious what's happening here. I wouldn't expect anything to delay object deinitialization in this situation.
Karl
(👑🦆)
6
What's quite interesting is that you can see it statically. I made a little demonstration using Godbolt.
In 5.0 and 5.1, the generated code looks like this:
main:
push rbp
mov rbp, rsp
call run_end@PLT
call in_student_deinit@PLT
call in_person_deinit@PLT
xor eax, eax
pop rbp
ret
But in 5.2, it changed to this, for some reason swapping the order of "run end" and the student's deinit:
main:
push rbp
mov rbp, rsp
call in_student_deinit@PLT
call run_end@PLT
call in_person_deinit@PLT
xor eax, eax
pop rbp
ret
Which is where it stayed all this time, including in 5.5 (the latest release on Godbolt). However, running it against nightly shows it has since been fixed:
main:
push rax
call run_end@PLT
call in_student_deinit@PLT
call in_person_deinit@PLT
xor eax, eax
pop rcx
ret
5 Likes
Both let and var instances are declared inside function scope. So in mental model they should both deinit after print("run end"). I suppose ARC optimizations come into play when -O optimization enabled, so let instance is deallocated earlier.
tera
8
Looks so. And this was the proposal to make behaviour more obvious and deterministic.
1 Like
Thanks for your answer.
Yes, according to WWDC Session 10216, in release mode, it is true, if the variable is not used, it will be released as early as possible. So the let variable should also be released in advance. In fact, it is released after the "run end". Curious, what is the reason for Apple's design?
Thanks for your answer.I'm just curious, according to WWDC Session 10216, in release mode, if the variable is not used, it will be released as early as possible. So the let variable should also be released early, in fact it is released after the "run end".
Thanks for your answer.
I am going to download the latest Swift 5.6 to verify.
Jumhyn
(Frederick Kellison-Linn)
13
It’s a bit subtle, but by my interpretation that WWDC session doesn’t contradict the behavior here. The speaker notes that “depending on the ARC optimizations that kick in, the observed lifetimes may differ from their guaranteed minimum” (4:50). Furthermore, the following section describes that precise object lifetimes should not be relied upon—beyond the guarantee of “strong reference will not be released before last use,” Swift does not currently promise much about object lifetimes. Though, as @tera notes, some moves have been made towards tightening guarantees in this area in future versions of Swift.
3 Likes
lvv.me
(lvv.me)
14
What compile argument for swiftc is equal to Optimize Object Lifetimes: YES in Xcode 13 ?
lvv.me
(lvv.me)
15
- Xcode 13 provided a Swift build setting called “Optimize Object Lifetimes” that’s not available in Xcode 14. If your project already customized this build setting, it now becomes a user-defined setting. It has no effect and you can remove it. Xcode 14 now consistently optimizes object lifetimes. (91971848)
It also removed in Swift 5.7 ?
2 Likes