views:

362

answers:

4
+6  A: 

IMO, Scala just gives more flexibility not mixing up immutability of the reference with [possible] mutability of the structure behind it, giving you ability to make a design decision WRT the problem you're dealing with.

Vasil Remeniuk
Are you saying C++ doesn't give this flexibility? This works just fine in C++: `const vector<Point*> v[0]->x++;`. constness of the data structure (vector) and the content (`Point`) are separate.
Ben Voigt
I'm talking about immutability of the data structure vs reference, not data structure vs its content. E.g., you cannot add/remove elements from immutable data structure, whereas mutation of the content (single elements) is possible.
Vasil Remeniuk
Which is entirely possible in C++. If you have a data structure `class Collection { T* elements; public: void const_func(int i) const; }` then there's no problem writing `void Collection::const_func(int t) const { elements[i]++; elements[i+1] = members[i-1]; }` Within a const member function, `this` has the type `const Collection* const this` and data members become `T* const elements` not `const T* const elements`. Also of course `const Collection*` is different from `Collection* const` which is the immutability of reference vs immutability of instance question you originally raised.
Ben Voigt
And of course if you say `class ImmutableCollection { const T* const elements; };` then the collection really is immutable and no one is adding or removing to an instance after construction.
Ben Voigt
+3  A: 
Margus
Similar structure should rather be `List` (from `scala.colleciton.immutable`) `val a = List(1, 2, 3, 4)`, that can on demand be converted to array `a toArray`
Vasil Remeniuk
Guess your right, I used set to indicate that in constant collection you probably do not want duplicates as well.
Margus
In C++ the compiler checks on const access. Trying to modify CONST in your example will pass compilation and fail at runtime
IttayD
That is called **Reification**, and that is just how Java does things.
Margus
"All Scala code is translated to Java code, that is why I made examples in Java." : definitely +1 for not making examples in ARM microcode or smth :)
mlvljr
The all upper case naming convention is only mandatory for primitive types and strings. For all other types it's optional.
Martin
Scala code is **never** translated to Java source code in the compilation process. It's compiled to Java **bytecode**, and there may not be any Java program that compiles into some of the bytecode that Scala generates.
Ken Bloom
+5  A: 

Because C++ const is not that great in complex systems.

I can be sure, that calling iPlusFive won't change the object and that I won't accidentally call incrementI on a const object.

No, you can't, because the implementation (which may be in a library somewhere out of sight) can cast the constness away. Without const, other languages have to enforce the immutability in safer ways (see Collections.unmodifiableList() in @Margus's answer, for instance).

Const is just documentation that the compiler reads. Documentation is usually helpful but sometimes misleading.

When it comes to collections, C++ continues it's const-correct streak with const collections: simply declare your vector as const and you can't change it.

Aggregation is where const often breaks down for me. I often want to declare, for instance, that a method will not change the vector but may change a member of it (or return a non-const member reference). I have to make it all const or all nonconst or invent new type variations for every combination.

'mutable' makes up for some of the aggregation issues but introduces more complexity and misuse.

xan
+8  A: 

The thing I dislike about C++ const logic is that it is about the reference and not about the object that is referenced. If I have a "const T *" there is no guarantee that someone holding a non-const pointer will not modify the state of the object. As such, it does not help in any way to avoid race conditions in multi-threaded systems nor does it help in implementing persistent containers.

In my opinion it is very helpful to have a concept of immutable classes and lack of immutable containers in a standard library is a mistake in any language. Since these should exhibit observable immutability but will likely need to be able to change internal/invisible state for efficiency reasons I think const-syntax would be of little help.

Scala has the immutable classes we need to either use directly or base other immutable classes on. That is extremely valuable. Additional syntax might be a nice addition but I can live without it.

Silvio Bierman
What are you talking about about? const T* - or better T const* as const works to the left makes T constant and leaves T* mutable. So unless someone uses an ugly hack - or you handed a non const pointer out of your class no one can change the data.
Martin
I am talking about being handed a const pointer to an object I do not own or control. Since I do not know if someone else holds a non-const pointer I am unable to modify the object but have no guarantee that it will not be modified.
Silvio Bierman
BTW: "const int *x" makes x mutable and *x immutable while "int *const x" makes x immutable and *x mutable.
Silvio Bierman
This <enter>-sensitive behaviour is getting to me... Your variant "int const *x" is a synonym for "const int *x".
Silvio Bierman
Martin is absolutely right that being handed a const pointer doesn't mean that no one else can change the object.
Ben Voigt
Which is what I said, was it not?
Silvio Bierman
I probably meant to type "@Martin: Silvio is absolutely right"... it was late at night. @Silvio: However your conclusions are flawed. C++ `const` definitely lets the caller (aka *controller*) reason about race conditions because it knows which callees have access to the object and whether that is read-only or write access. Having the callee know whether others can mutate the object leads to synchronization logic in the callee, C++ `const` leads to synchronization logic in the caller, and the C++ way is at least as valid as the other.
Ben Voigt
Yes Ben, that is correct but as the caller I can also achieve such by passing a limited interface on the object that only permits read-access. IMO the problem of reasoning about the state of objects accessed concurrently from multiple locations in multiple threads is a much bigger problem to solve than caller/callee logic.
Silvio Bierman