0

As everyone knows, JavaScript "Hoists" the variables to the top of the file or scope. But from my understanding, using let is the same as var only let is confined to the scope it is defined in.

Being a compiled language instead of an interpreted, can we assume Swift does NOT do this?

For example:

x = 10

var y = x + 10

var x
nhgrif
  • 61,578
  • 25
  • 134
  • 173
devtech
  • 325
  • 1
  • 12
  • Your question is a bit confusing to me, but assuming there is not another declaration of `x` anywhere else, this won't compile in Swift. http://i.imgur.com/rrjHvS8.png – nhgrif Feb 02 '16 at 12:57
  • 1
    I've found this useful: [What is the difference between `let` and `var` in swift?](http://stackoverflow.com/questions/24002092/what-is-the-difference-between-let-and-var-in-swift) – Volkan Paksoy Feb 02 '16 at 13:10
  • 1
    @MartinR I think OP is referring to the behaviour of JavaScript and asking if the behaviour is the same in Swift - one key difference is that `var` (in JS) hoists variables to the nearest function scope; `let` does not, and is block scoped instead. In this sense, the main difference between the two is the scope they are accessible in. Still, the question is founded on an incorrect assumption: This behaviour isn't because JavaScript is compiled or interpreted, it's because `var` had a weird specification. – Dan Feb 02 '16 at 13:51
  • @DanPantry: You are right, I did not read the question correctly. I apologize for that and I'll remove my comment and the closing vote. – However, I still don't consider it a good question because OP could have checked quickly that it does not work like that in Swift. – Martin R Feb 02 '16 at 13:59
  • 1
    @MartinR Not looking to debate whether or not it's a good question - just hoping to clear up any ambiguities :) – Dan Feb 02 '16 at 14:02

2 Answers2

7

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.

Community
  • 1
  • 1
nhgrif
  • 61,578
  • 25
  • 134
  • 173
2

'let' and 'var' do not have a difference in scope.

Global variables are variables that are defined outside of any function, method, closure, or type context. Local variables are variables that are defined within a function, method, or closure context.

Eppilo
  • 763
  • 6
  • 19