The variables in top-level code behave weirdly. They are declared in the global scope, but are initialized serially, like local variables in a normal function. This allows some interesting pieces of code to compile, such as:
print(x)
var x = 32
This program will print 0
. The basic value types are automatically initialized, so they have a value. However, if x
is a class, this results in a crash. Clearly, this is not an ideal situation. You shouldn't be able to use variables before they are initialized, let alone before they are declared.
My thoughts are to make the top-level variables behave like local variables inside of an implicit function.
Before prescribing a change in the form of a pitch, I have a few questions that I would like to ask the forum.
-
Are you relying on variables in top-level code behaving as global variables? (How and why?)
-
In wrapping the top-level code in an implicit main function, are any functions declared in that space nested inside of this main function, or are they global?
The following code would implicitly behave like the following:
var x = 32
func foo() {
print("Hello World \(x)")
}
In the nested form:
@main struct Main {
static func main() {
var x = 32
func foo() {
print("Hello World \(x)")
}
}
}
Un-nested:
func foo(_ x: Int) {
print("Hello World \(x)")
}
@main struct Main {
static func main() {
var x = 32
foo(x)
}
}
Note that in the un-nested form, x
is not visible from foo
, so you would need to pass it in directly.
This is a departure from how top-level code has behaved previously, but is easier to reason about once concurrency is a factor.
Before prescribing a change, I would like to get your thoughts on the matter and hear if anyone is relying on this behaviour. If you are, how and why?
Given that this is source breaking, changes here would be a change for Swift 6 at the earliest.