A number of languages have support for immutable types – once you have constructed the value of such a type, it cannot be modified in any way. I won't digress into the benefits of such types, as this has been discussed extensively elsewhere. (See e.g. http://codebetter.com/patricksmacchia/2008/01/13/immutable-types-understand-them-and-use-them/ )
I would like to create a lightweight immutable record type in C++. An obvious way of doing this would be to const
all the members. For example:
struct Coordinates {
const double x;
const double y;
};
Unfortunately, a type declared in this way doesn't support copy assignment, and as such can't be used with STL containers, which is a pretty fatal drawback. I don't think there is any way around this, but would be grateful to know if anyone can see one.
For what it's worth, as far as I can see, C++ is conflating two things: a) whether you can assign a new value to a variable, and b) whether "values" (=objects) can be modified after they are constructed. The distinction is much clearer in e.g. Scala, where one has
val
vs var
: a var
can have a new value bound to it, a val
cannotSo I can write the following:
val val_mutable = collection.mutable.Map(1 -> "One")
val val_immutable = collection.immutable.Map(1 -> "One")
var var_mutable = collection.mutable.Map(1 -> "One")
var var_immutable = collection.immutable.Map(1 -> "One")
var
s can be rebound to point at other values:
//FAILS: val_immutable = collection.immutable.Map(2 -> "Two")
//FAILS: val_mutable = collection.mutable.Map(2 -> "Two")
var_mutable = collection.mutable.Map(2 -> "Two")
var_immutable = collection.immutable.Map(2 -> "Two")
mutable collections can be modified:
val_mutable(2) = "Two"
//FAILS: val_immutable(2) = "Two"
var_mutable(2) = "Two"
//FAILS: var_immutable(2) = "Two"
In C++, const
ing the data members of a type makes it an immutable type but also makes it impossible to create "var"s of that type. Can anyone can see a reasonably lightweight way of achieving the former without the latter? [Please note the "lightweight" part -- in particular, I do not want to create an accessor function for every element of the struct
, as this results in a massive drop in readability.]
You mention that you can't use the Coordinates
class with STL containers as written with const
members. The question of how to do that is answered (inconclusively) here:
https://stackoverflow.com/a/3372966/393816
The same suggestion, which is to make your instances const
rather than your members, has been made in comment threads on this question too. I agree with your comment that it is less reliable since you must change more code, but perhaps you could use a typedef like so:
struct MutableCoordinates {
double x;
double y;
};
typedef const MutableCoordinates Coordinates;
So that users of Coordinates
objects automatically get the immutable version unless they explicitly as for it? This would offset some of your worry about the verbosity of using the struct safely.
Of course, you can also switch to reference semantics by using shared_ptr
, which will work very well with const
objects since the different references can't mess with each other, but it comes with the overhead of manual memory allocation which is rather excessive for a struct of two double
s.