Reputation: 10291
In C++. I can declare most things as const, for example:
Variables: const int i=5;
Scala has val i=5
, however this will only prevent reassigning, not changing the object as the following exampe shows:
C++:
const int i[]={1,2,3,4};
i[2]=5; //error
Scala: val a=Array(1,2,3,4)
a(2)=5 //a is now Array(1, 2, 5, 4)
It gets even worse with member functions:
C++:
class Foo {
int i;
int iPlusFive() const {return i+5;}
int incrementI(){ return ++i; }
}
I can be sure, that calling iPlusFive won't change the object and that I won't accidentally call incrementI on a const object.
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. Assign a non-const vector<Int>
to a const vector<Int>
and the compiler won't copy anything and will prevent you from changing anything in the now const collection.
Scala has scala.collection.mutable.whatever and scala.collection.immutable.whatever, you can't just convert mutable collections to immutable collections, furthermore you're still allowed to change the collected objects with their non-const member functions.
Why does scala, which has an otherwise really great type-system, not have anything comparable to C++ const-keyword?
Edit:
Margus suggested using import scala.collection.mutable
.
My solution was to use
import scala.collection.mutable.HashMap
import scala.collection.immutable.{HashMap => ConstHashMap}
This will make the mutable HashMap available as HashMap and the immutable als ConstHashMap, however I still like the C++ approach better.
Upvotes: 20
Views: 2262
Reputation: 20048
All Scala code is translated to Java code, that is why I made examples in Java.
This is how to do this in Java:
Integer x[] = new Integer[]{1,2,3,4};
final List<Integer> CONST = Collections.unmodifiableList(Arrays.asList(x));
So what is happening you ask? CONST is 1 step away from actual array, and it enables to hide actual array and the Collection elements, where as using a simple array, this would not be possible. If you would still want to modify constant collection you would need to make a copy of it and modify that.
Source: link
Array with unmodifiable contents?
Java doesn't provide the notion of a const array: that is, an array that can be swapped for a new array (in C++ terms, "the pointer can be modified"), but whose elements can't be changed. However, if you need this functionality, the solution is generally much like providing read-only access to any other object as discussed below. So a couple of possibilities are:
- you can create an unmodifiable list by passing a list into Collections.unmodifiableList() (though in this case, the variable would be declared of type List, not of a type that marked it as "unmodifiable"— as discussed below, any attempt to modify it would be spotted at runtime);
- you can create a wrapper object around a private array, and provide public methods to read but not write its elements;
- you can use a read-only IntBuffer (or FloatBuffer etc): ...
Source: Java equivalents - const from c++ perspective.
So equivalent for Scala is:
val A = Set(1, 2, 3, 4)
val A = List(1, 2, 3, 4)
This should translate to:
scala.collection.immutable.List[java.lang.Integer] A = List(1, 2, 3, 4)
This might explain my response to IttayD comment, why java 6 differs from c++ compiler:
Reified Generics
Currently, generics are implemented using erasure, which means that the generic type information is not available at runtime, which makes some kind of code hard to write. Generics were implemented this way to support backwards compatibility with older non-generic code. Reified generics would make the generic type information available at runtime, which would break legacy non-generic code. However, Neal Gafter has proposed making types reifiable only if specified, so as to not break backward compatibility.
Source: link
Silly to even mention, but Java Constant Naming Conventions is to use uppercase for the variable. Others reading your code will immediately know that the identifier is a fixed, constant value that cannot be changed.
Source: link
... you can't just convert mutable collections to immutable collections, ...
A useful convention if you want to use both mutable and immutable versions of collections is to import just the package collection.mutable.
import scala.collection.mutable
Source: Scala Collection API
Not sure what you mean by converting, but you can probably do:
val a = scala.collection.mutable.List[Int](1, 2, 3)
val A = scala.collection.immutable.List[Int](a.toArray())
Upvotes: 3
Reputation: 713
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.
Upvotes: 11
Reputation: 7731
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.
Upvotes: 6
Reputation: 20617
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.
Upvotes: 5