lovee
(Elvis Shi)
1
Until Swift 5.1 this piece of code will cause build error, which totally makes sense:
do {
defer { print(a) } // `a` is not declared at this point
let a = 0
}
But from Swift 5.2, the same code can be compiled with a warning message that says a was never used; and from Swift 5.3 even the warning message disappears.
I tried to search for proposals related to this modification but had no luck.
6 Likes
Jens
2
I might be missing something, but I don't see why it shouldn't compile.
This compiles and behaves as expected:
func test() {
if Bool.random() { return }
defer { print(a) }
let a = 123
}
test()
And this results in an error, also as expected:
func test() {
defer { print(a) } // Error: 'defer' block captures 'a' before it is declared
if Bool.random() { return }
let a = 123
}
test()
I noticed that the following program crashes the compiler when compiled with -O (but works fine in debug) though:
func test() {
defer { a += 1; print(a) }
var a = 123
}
test()
% swiftc --version
Apple Swift version 5.4.2 (swiftlang-1205.0.28.2 clang-1205.0.19.57)
Target: x86_64-apple-darwin20.5.0
% swiftc test.swift
% ./test
124
% swiftc -O test.swift
Please submit a bug report (https://swift.org/contributing/#reporting-bugs) and include the project and the crash backtrace.
Stack dump:
...
jrose
(Jordan Rose)
3
Because it gets confusing with shadowing:
func test(_ flag: Bool) {
let a = 1
if flag {
defer { print(a) } // prints 1
let a = 2
}
}
test(true)
2 Likes
michelf
(Michel Fortin)
4
Fun exercice: can we guess what this one will print?
func test(a: Int = 456) {
defer { print(a) }
let a = 123
}
test()
Result:
3 Likes
Jens
5
So what should the correct behavior be? None of these examples should compile?
BigSur
({ @MainActor in M1.Ultra }(Swift))
6
func test(a: Int = 456) {
defer { print(a) } //456
let a = 123
defer { print(a) } //123
}
123
456
func test(x: Int = 456) {
defer { print(a) } //123
let a = 123
defer { print(a) } //123
}
123
123
1 Like
xwu
(Xiaodi Wu)
7
It seemed a reasonable feature until Jordan pointed out the shadowing problem. Obviously, it wouldn't be good to silently change the behavior of existing code, and one would want let a = 123; defer { print(a) } not to change because of code that's written below it. I'd conclude, then, that the best path forward with the examples of use before declaration would be a deprecation warning that eventually becomes a compilation error again.
5 Likes
Yeah, I agree -- this seems like a compiler bug to me.
3 Likes