Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Then what is the point of having let vs var at all? I think the solution they came up with is the correct one given the design of swift and its use of let and var keywords.


let v var has to do with mutable bindings, value mutability within the bindings should be a separate concern.

Rust makes that exact difference[-1]: `mut` can be used either at the binding level

    let mut a: ∫
or at the type level:

    let b: &mut int = &mut 1;
Both are references (~pointers) to an int, but `a` is a mutable reference, it can be changed to point to a new value[0]:

    a = &2;
because b is an immutable reference it can't point to a new value and

    b = &mut 2;
is a compilation error:

     error: re-assignment of immutable variable `b`
however b's value can be modified in place:

    *b += 1;
whereas trying that with a:

    *a += 1;
is an error:

    test.rs:5:5: 5:7 error: cannot assign to immutable dereference of `&`-pointer `*a`
`a` is a mutable reference to an immutable value, `b` is an immutable reference to a mutable value.

[-1] and so does C though it has the opposite defaults, you can have an

    int const *
— a mutable pointer to an immutable int (you can reassign the pointer but not change the pointee) — and an

    int * const
— an immutable pointer to a mutable int (you can't reassign the pointer but you can alter the pointee)

[0] the code does not work as-is because lifetimes, but close enough


I didn't appreciate that Rust makes that distinction, that really is quite elegant.

By way of comparison (to Rust and the original article), here is Scala:

    scala> val a = scala.collection.immutable.Set("apple", "orange")
    a: scala.collection.immutable.Set[String] = Set(apple, orange)

    scala> a = Set()
    <console>:8: error: reassignment to val
           a = Set()
             ^

    scala> val b = scala.collection.mutable.Set("cherry", "plum")
    b: scala.collection.mutable.Set[String] = Set(cherry, plum)

    scala> var c = b
    c: scala.collection.mutable.Set[String] = Set(cherry, plum)

    scala> b += "pear"
    res6: b.type = Set(pear, cherry, plum)

    scala> c
    res7: scala.collection.mutable.Set[String] = Set(pear, cherry, plum)

    scala> c = a
    <console>:10: error: type mismatch;
     found   : scala.collection.immutable.Set[String]
     required: scala.collection.mutable.Set[String]
           c = a
               ^
In other words: var versus val has to do with mutable bindings; mutable bindings allow you to mutate the value but not the type; object mutability within the bindings is governed by the object's own type (as the original author recommended for Swift).


The different types of mutability are also quite important for the concept of "borrowing" in Rust, which is simply taking a reference. The compiler ensures that ownership of the variable isn't transferred while any such reference is active, and only one mutable reference (of a mutable type) can exist at any one time. This means that bugs like that shown for Swift are impossible in Rust, because the language ensures no two things can ever modify it at the same time.


let/var solve a different problem than the question of whether the array itself is mutable. Look back at the OP, and in particular at the last example section, which lays out the behaviour of various combinations of let/var with mutable/immutable arrays. Each of these behaviours is desirable in different circumstances, and more importantly, by separating the concerns here it will make the language semantics easier to understand and apply to new examples.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: