How exactly does the "let" keyword work in Swift?

It's best to think of let in terms of Static Single Assignment (SSA) -- every SSA variable is assigned to exactly once. In functional languages like lisp you don't (normally) use an assignment operator -- names are bound to a value exactly once. For example, the names y and z below are bound to a value exactly once (per invocation):

func pow(x: Float, n : Int) -> Float {
  if n == 0 {return 1}
  if n == 1 {return x}
  let y = pow(x, n/2)
  let z = y*y
  if n & 1 == 0 {
    return z
  }
  return z*x
}

This lends itself to more correct code since it enforces invariance and is side-effect free.

Here is how an imperative-style programmer might compute the first 6 powers of 5:

var powersOfFive = Int[]()
for n in [1, 2, 3, 4, 5, 6] {
    var n2 = n*n
    powersOfFive += n2*n2*n
}

Obviously n2 is is a loop invariant so we could use let instead:

var powersOfFive = Int[]()
for n in [1, 2, 3, 4, 5, 6] {
    let n2 = n*n
    powersOfFive += n2*n2*n
}

But a truly functional programmer would avoid all the side-effects and mutations:

let powersOfFive = [1, 2, 3, 4, 5, 6].map(
    {(num: Int) -> Int in
        let num2 = num*num
        return num2*num2*num})

First of all, "The let keyword defines a constant" is confusing for beginners who are coming from C# background (like me). After reading many Stack Overflow answers, I came to the conclusion that

Actually, in swift there is no concept of constant

A constant is an expression that is resolved at compilation time. For both C# and Java, constants must be assigned during declaration:

public const double pi = 3.1416;         // C#
public static final double pi = 3.1416   // Java

Apple doc ( defining constant using "let" ):

The value of a constant doesn’t need to be known at compile time, but you must assign the value exactly once.

In C# terms, you can think of "let" as "readonly" variable

Swift "let" == C# "readonly"


let is a little bit like a const pointer in C. If you reference an object with a let, you can change the object's properties or call methods on it, but you cannot assign a different object to that identifier.

let also has implications for collections and non-object types. If you reference a struct with a let, you cannot change its properties or call any of its mutating func methods.

Using let/var with collections works much like mutable/immutable Foundation collections: If you assign an array to a let, you can't change its contents. If you reference a dictionary with let, you can't add/remove key/value pairs or assign a new value for a key — it's truly immutable. If you want to assign to subscripts in, append to, or otherwise mutate an array or dictionary, you must declare it with var.

(Prior to Xcode 6 beta 3, Swift arrays had a weird mix of value and reference semantics, and were partially mutable when assigned to a let -- that's gone now.)


Let


Swift uses two basic techniques to store values for a programmer to access by using a name: let and var. Use let if you're never going to change the value associated with that name. Use var if you expect for that name to refer to a changing set of values.

let a = 5  // This is now a constant. "a" can never be changed.
var b = 2  // This is now a variable. Change "b" when you like.

The value that a constant refers to can never be changed, however the thing that a constant refers to can change if it is an instance of a class.

let a = 5
let b = someClass()
a = 6  // Nope.
b = someOtherClass()  // Nope.
b.setCookies( newNumberOfCookies: 5 )  // Ok, sure.

Let and Collections


When you assign an array to a constant, elements can no longer be added or removed from that array. However, the value of any of that array's elements may still be changed.

let a = [1, 2, 3]
a.append(4)  // This is NOT OK. You may not add a new value.
a[0] = 0     // This is OK. You can change an existing value.

A dictionary assigned to a constant can not be changed in any way.

let a = [1: "Awesome", 2: "Not Awesome"]
a[3] = "Bogus"             // This is NOT OK. You may not add new key:value pairs.
a[1] = "Totally Awesome"   // This is NOT OK. You may not change a value.

That is my understanding of this topic. Please correct me where needed. Excuse me if the question is already answered, I am doing this in part to help myself learn.