28

I've read this simple explanation in the guide:

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

But I want a little more detail than this. If the constant references an object, can I still modify its properties? If it references a collection, can I add or remove elements from it? I come from a C# background; is it similar to how readonly works (apart from being able to use it in method bodies), and if it's not, how is it different?

Jamal
  • 763
  • 7
  • 22
  • 32
Max Yankov
  • 12,551
  • 12
  • 67
  • 135
  • It seems to mean that you can not change the var, but if the var points to an object you should deb able to make changes to the object in the same manner as objects accesses in the scope of a block. IOW, it a var points to a mutable array the values in the array should be able to be changed. – zaph Jun 02 '14 at 20:53
  • If you're coming from C#, then it would have the same meaning as "readonly var", if that was allowed. Or "let" in F#. – Asik Jun 04 '14 at 21:11
  • possible duplicate of [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) – nhgrif Jun 16 '15 at 00:24
  • Yes you can still modify the properties, dependending on how they were configured. This works similarly to `const` in JavaScript. A field can generally still be modified unless it was frozen/sealed or marked as non-writable. – james_womack Jun 11 '16 at 05:17

6 Answers6

48

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.)

rickster
  • 124,678
  • 26
  • 272
  • 326
  • do you know if the behavior is consistent with `NSDictionary`/`NSMutableDictionary` ? – Jiaaro Jun 02 '14 at 21:15
  • consistent in what way? – rickster Jun 02 '14 at 21:22
  • well… I guess I should have asked: are there any notable inconsistencies? (performance, methods, etc) – Jiaaro Jun 03 '14 at 15:44
  • 2
    That's peculiar, you can change array defined with let, but you cannot change dictionary defined with let. – Maciej Jastrzebski Jun 03 '14 at 19:01
  • 1
    Update: From XCode 6 beta 3 onwards, you also cannot substitute values in arrays defined with let, so it seems more consistent now. Source: https://functionwhatwhat.com/breaking-changes-to-swift-in-xcode-6-beta-3/#newvaluesemanticsforarrays – garyc40 Jul 15 '14 at 02:16
  • Thank you for the analogy between 'let' and the C 'const pointer', that's helpful. – Goffredo May 01 '23 at 08:33
5

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})
wcochran
  • 10,089
  • 6
  • 61
  • 69
  • 1
    Lisp definitely has assignment, and values can be assigned to a variable many times. – newacct Jul 17 '14 at 05:01
  • Yes Lisp certainly does allow assignment ( eg setf), but functional programmers only use it when it's truly necessary... which does happen. – wcochran Jul 17 '14 at 05:33
4

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.

  • 3
    Sorry but I think your example of _Let and Collections_ with the array example is incorrect as, mutability is not allowed for `a[0] = 0`, so this is NOT OK. – Vlad Apr 24 '16 at 11:34
3

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"

MD TAREQ HASSAN
  • 1,188
  • 20
  • 46
0

F# users will feel right at home with Swift's let keyword. :)

In C# terms, you can think of "let" as "readonly var", if that construct was allowed, i.e.: an identifier that can only be bound at the point of declaration.

Asik
  • 21,506
  • 6
  • 72
  • 131
0

Swift properties:

Swift Properties official documentation

In its simplest form, a stored property is a constant or variable that is stored as part of an instance of a particular class or structure. Stored properties can be either variable stored properties (introduced by the varkeyword) or constant stored properties (introduced by the let keyword).

Example:

The example below defines a structure called FixedLengthRange, which describes a range of integers whose range length cannot be changed once it is created:

struct FixedLengthRange {
    var firstValue: Int
    let length: Int
}

Instances of FixedLengthRange have a variable stored property called firstValue and a constant stored property called length. In the example above, length is initialized when the new range is created and cannot be changed thereafter, because it is a constant property.

d.danailov
  • 9,594
  • 4
  • 51
  • 36