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.
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:
...
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.