can we assume Swift does NOT do this?
You can assume whatever you want, but no matter the programming language, your absolute best bet it to just try it and find out. If you would have pasted your sample code into a Playground or in any Swift-capable IDE, or just tried running it through the command line, you'd quickly find out that this simply does not work.
Your question is somewhat confusing, but I think I can address all or at least most of your questions.
x = 10
var y = x + 10
var x
Assuming there is no other code to go with your original sample, it simply does not compile. All three lines have a problem.
The first two lines complain about the use of an unresolved identified 'x'. In English, this means Swift can't figure out what variable you're talking about. Variables in Swift must be declared before they are used, so the declaration on line three doesn't help the next two lines.
The third line complains that it can't figure out what type x
should be. "Type annotation missing in pattern". In some cases, Swift can figure out what type our variable should be. For example, with var x = 10
, Swift can figure out that x
's type should be Int
. If we want something else, we must specify. But if we aren't assigning a value in the declaration, Swift has no idea and must be told: var x: Int?
What about the case where x
exists at a different scope?
Well, Swift allows variable shadowing. That is to say, a variable declared at one scope hides a variable declared at another scope.
So, for example:
class Foo {
let x = 10
func foo(value: Int) -> Int {
let a = value * self.x
let x = 10
return a * x
}
}
Now we can use some x
before we've declared a locally scoped x
, but these are different variables. Also, perhaps most importantly, notice the self.
prepended to x
here. It's required. Without it, Swift will refuse to compile this code and will complain: "Use of local variable 'x' before its declaration."
However, within functions of classes is not the only place we can shadow variables. We can also do it within if
blocks (among other places) which is where things can get a little more confusing. Consider this:
class Foo {
let x = 10
func foo(value: Int) -> Int {
print(x)
if x > 3 {
let x = 2
print(x)
}
return x
}
}
Here, we've used x
twice before declaring it. And we didn't have to make use of the self.
and it doesn't complain and compiles perfectly fine. But it's important to note that outside the if
block (including the x > 3
conditional) the x
we're referencing is the instance variable, but inside the if
block, we've created a new variable called x
which shadows the instance variable. We can also create the same sort of shadowing by using if let
and if var
constructs (but not guard let
).
The result of calling this function will be that the value 10
is printed, we enter the if
block, the value of 2
is printed, then we exit the if
block and the value of 10
is returned.
Now let's through var
into the mix here. First, if you aren't already aware, you should start by reading this which explains the difference between let
and var
(one is a constant, the other is not).
Let's combine let
vs var
with scoping and variable shadowing to see how it effects things.
class Foo {
let x = 10
func foo(value: Int) -> Int {
print(x)
if x > 3 {
var x = 2
while x < 10 {
print(x)
x += 3
}
return x
}
return x
}
}
Okay, so this is the same as before but with a slightly more complicated bit within the if
block.
Here, our locally-scoped variable is declared as a var
while our instance variable remains a constant let
. We cannot modify the instance variable, but we can modify the local variable. And we do so, on each iteration of the while
loop.
But importantly, this variable is an entirely different variable from the instance variable. It might as well have a completely different name (and in practice, it basically always should have a different name). So modifying our local variable x
doesn't change anything about our more broadly scoped instance variable x
. They're different variables that reside in different memory locations. And once a variable is declared as a let
or a var
, that variable cannot be changed to the other.