One of my biggest remarks when working with Java the past few years was the lack of a strict immutability concept. The most you can do is declare your object to be final, which only prevents changing the object being pointed to and not any changes made to the object itself. I remembered that C++ offered a lot more opportunities for this and you could go crazy with the ‘const’ keyword.
However, during some quick investigation regarding this constant behaviour for the GroceriesInsight project, I discovered that I was a bit off with how C++ handles the constant behaviour of arguments passed to a function.
If a method requests a pointer to const variable, it can not change the value of the variable. This is the definition of the const key-word, however it is possible for the caller to pass a pointer to a mutable object. So even though the callee can not change the object, there is no guarantee that the caller can not do so. This is a result of the specification that states that the const keyword is part of the type.
It is obvious that the opposite can never be true, you can not pass in an immutable object to a function that wants a mutable object, at least not without doing some const-casting magic.
What I would have liked was a way to let the function request an immutable object, such that it is safe to store it without worrying about the caller changing it, or passing it on to other functions or objects that can change it. With this definition of constant this is however impossible and such guarantees can never be given, as it will always be that case the changes made by the caller have an effect on the callee. There are of course two simple ways to solve this issue:
- Do not pass a pointer, but an actual object.
- Take a copy of the object.
Both of them will make a local copy of the object such that the callee can use that and be assured that changes made by other parts of the application will not affect it. A small remark with these approaches however is they way in which the object is copied, either shallow or deep.
The whole idea of using the const keyword with an argument is to let the caller know that the callee will not change the object, which is of course equally important. It is the callee that guarantees that the caller doesn’t have to worry about changes made to the object it passes on.
The logic here is that the method tells the caller how it will use the parameter, by using the const-keyword the caller can be assured that the method will not alter the parameter. This behaviour is actually very similar to Java where a method that specifies an argument as final can not change the object it points to, but the caller can still pass a non-final object.
In an object-oriented program. where the passed argument is saved as a member of the object, it is essential that the object knows that it will not change behind its back. It is the responsibility of the object to guarantee consistency and it can not do so if some external component can alter its internal data. So whenever you face this scenario, you should either take a copy of the object, or alternatively change your design to let the object itself create the object rather than passing it in as an argument
This last thing is what I plan on doing, but in my case it makes sense to do so. Especially because the caller currently just creates the object with the sole purpose of passing it on to the object. It might however become tricky to pass in all the data that makes up the object, passing it all separately as arguments may cause the argument list to become too big. The builder pattern could be useful to take care of this.