Anu
Anu

Reputation: 46

Initializing variables in Swift without var/let

I'm new to Swift so this might come as a noob question but I will be thankful if someone cleared the doubt because I cannot find any explanation online. While using for-in loop, sometimes the variables have not been initialized before and still there is no compiler error. Sometimes if I try to write var/let before them, it shows error- 'let' pattern cannot appear nested in an already immutable context

e.g., in the code below, why have the variables movie and releasedDate not been initialized before?

class MovieArchive {
func filterByYear(year:Int, movies:Dictionary<String, Int> ) -> [String]{
    var filteredArray = [String]()
    for (movie, releaseDate) in movies {
        if year == releaseDate {
            filteredArray.append(movie)
        }
    }
    return filteredArray
}

}

var aiThemedMovies = ["Metropolis": 1927, "2001: A Space Odyssey": 1968, "Blade Runner": 1982, "War Games": 1983, "Terminator": 1984, "The Matrix": 1999, "A.I.": 2001, "Her": 2013, "Ex Machina": 2015]

var myArchive = MovieArchive()
myArchive.filterByYear(year: 2013
, movies: aiThemedMovies)

Thanks in advance for any help :)

Upvotes: 1

Views: 1075

Answers (3)

matt
matt

Reputation: 535766

Without concerning ourselves with practical usage, let's just talk about what is syntactically legal in a for loop. This is legal:

    for var i in 1...3 { // ok
        print(i)
        i = 0
    }

This is not legal:

    for let i in 1...3 { // error
        print(i)
    }

Why? Because the let is implicit when you say this:

    for i in 1...3 { // ok
        print(i)
    }

You didn't say var, so i is automatically declared with let. It's just a way of making your life simpler. Don't worry, be happy.

Upvotes: 1

Tometoyou
Tometoyou

Reputation: 8386

Swift does initialise movie and releaseDate using let, but simplifies that initialisation so that you can just assume that they're set to the correct variables from movies every time the loop iterates. That's why you don't need to write let before movie and releaseDate.

If you write var in front of the variable, you can mutate the value in the array that it points to. If it's a let, then it won't let you mutate it.

For example, if you place var in front of one of the variables, this code will change all the releaseDates to 2000:

class MovieArchive {
    func filterByYear(year:Int, movies:Dictionary<String, Int> ) -> [String]{
        var filteredArray = [String]()
        for (movie, var releaseDate) in movies {
            releaseDate = 2000
            if year == releaseDate {
                filteredArray.append(movie)
            }
        }
        return filteredArray
    }
}

Upvotes: 1

Cœur
Cœur

Reputation: 38717

(movie, releaseDate) is a tuple of variables. Swift allows initialising multiple variables at once using tuples.

let (movie, releaseDate) = ("Metropolis", 1927)

A for-in loop is syntactic sugar to redeclare those constants for each element of your collection. In that case, let is implicit.

There are other ways to get named constants with implicit let, like using a closure:

class MovieArchive {
    func filterByYear(year: Int, movies: [String: Int]) -> [String] {
        return movies.filter { (movie, releaseDate) -> Bool in
            year == releaseDate
            }.map { $0.key }
    }
}

The above example gives the same results as your code by the way.

But apart from for-in, func parameters and closures, I can't think of other cases where the let/var keyword would be omitted in Swift 3.0.

Upvotes: 0

Related Questions