Hacker News new | past | comments | ask | show | jobs | submit login

Minor nitpick:

> Immutability (const) by default

The author clearly knows this, but others may not, so: immutability and "const" aren't the same thing. Const typically prevents name rebinding (as the type system permits). Immutability is the presumption that the whole data structure can't be mutated by default (though there are usually ways to mutate cheaply--without bulk copying, that is--provided by most immutable data APIs).

Const works like this:

  not_const int[] foo = [123, 456]
  const int[] bar = [456,789]
  foo = [1,2,3]     // no problem; rebinding is allowed if it meets the 'int' type constraint.
  bar = [1,2,3]     // compile error!
Immutability, as typically defined (there's a bit of a semantic debate here sometimes) prevents changes to the contents of complex data structures:

  mut int[] foo = [123, 456]
  not_mut int[] bar = [456,789]
  foo[0] = 789    // no problem; mutation is allowed so long as it's with valid types.
  bar[0] = 123    // compile error!
Edit: missed a space.



Const typically prevents name rebinding (as the type system permits).

In C++ you can only call `const` methods through a const binding. `const` methods mark `this` const, so such methods cannot modify member variables. (Minus all escape hatches, such as `const_cast`.)

The author clearly knows this, [...] Immutability is the presumption that the whole data structure can't be mutated by default

The situation in Rust is a bit more complex. Rust distinguishes between interior and exterior mutability.

`let mut` bindings and `&mut` references exhibit exterior mutability - you can call methods that borrow `self` mutably (`&mut self`). Whereas `let` bindings and `&` references cannot. By the way, you can simply use moves to introduce exterior mutability for data that you own:

    let a = Vec::new();
    // Not allowed: a.push(1);
    
    // Move the vector.
    let mut b = a;
    b.push(1);
Even even if a data type uses an immutable binding or reference, it could still mutate that data structure if it has interior mutability (you just can't call methods that use self mutably). See the following small example, which uses an immutable binding to call a method that mutates the internal state of the struct.

https://play.rust-lang.org/?gist=6816dc9a03aca1e779f08443224...

The downside of interior mutability is that borrowing rules are enforced at run-time rather than compile-time.


C++ also has the `mutable` as a way to achieve something akin to internal mutability


It's interesting that Rust doesn't have immutable data. It "only" prevents shared mutable data, but you can always mutate data if nobody else can observe it:

    let bar = [456, 789]; // const binding to owned data
    let mut bar = bar; // allowed if nobody else can see `bar`
    bar[0] = 123; // OK!
Immutability in Rust is not property of the data, but the way you access it.


This explanation of const sounds much like Java's final, but not like C++'s const guarantees, which enable you to guarantee nobody downstream of a const modified reference will be allowed to perform a write operation through that reference.

You cannot get around that behavior by assigning the reference to a non-const copy. That isn't allowed.


But if some other code gets a non-const reference to an object via another pointer path, that code can mutate the object, even though const pointers to that object may exist. In Rust, this is not the case.

That difference severely weakens the meaning of the const property in C++.


See my comment below for how to prevent this: https://news.ycombinator.com/item?id=16550209


Your definition is at odds with C++ (one of the most widely used languages of all time), and its use of `const`.

C++'s const is your "immutability".


No. C++ const just means "I won't mutate this object" (through the const pointer). It doesn't mean that somebody else won't mutate the some object (through their non-const pointer to the same object).


That's not always true.

  struct X {
    const int i{123};
    const int j;

    X(int j_) : j{j_} {}
  };

  // non-const object; x.i == 123; x.j == 111
  X x{111};
  x.i = 222; // compilation error
  x.j = 333; // compilation error


And a more idiomatic example:

  struct X {
    X(Y val) : y_{val} {}

    // Can be called on const and non-const X objects
    const Y& y() const { return y_; }

    // Can only be called on non-const X objects
    Y& y() { return y_; }

  private:
    Y y_;
  };

  void f(X& x) { x.y() = 222; }
  void g(const X& x) { x.y() = 222); }

  const X x{123};  // x.y() == 123
  x.y() = 222; // compilation error
  f(x); // compilation error (f's parm is non-const)
  g(x); // compilation error (can't assign to const ref)

  // Cannot take non-const ref or ptr of x
  X& xr{x};  // compilation error
  X* xp{&x}; // compilation error
If the original declaration of the variable is const nothing can modify it. (And as my first example shows, the original declaration can always be const if you want it to be, regardless of context.) You can't take a non-const pointer or reference to x without explicitly circumventing the language like this:

  X& xr{const_cast<X&>(x)};
  X* xp(const_cast<X*>(&x)};


Sure, if the object was declared const in the first place, then it (mostly) can't be mutated. But the real power of const comes from const references, which in Rust guarantee that the referenced object will not be mutated while the reference is alive, even though it might have been mutated before.


I see. That's a nice feature.


You're thinking of a const pointer or reference. Of course if the data the pointer is pointing at changes, if you dereference it you get something else. But notice: the pointer, ie. the page number of your book, or the offset in your array, did indeed remain const. It is just the contents of the book/array that changed.

So, a const value cannot be mutated locally or globally. So if you make something const and expose it, it cannot be changed.


So in the const example, bar[0] is mutable? If not, I don't get your point.




Join us for AI Startup School this June 16-17 in San Francisco!

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

Search: