Introduction
I've been trying to summarize differences between how C#, Java and C++ do similar things to help me switch between languages on different projects. I often support or write new apps using one of these three, and it always takes me a week or so to remember all nuances and caveats necessary to get my code working !
So today this one is about const and read only, and a little final.
Background
When writing code we sometimes want things to be immutable, that means they should not change when the program is running. For some things this mirrors real life, for example the value that represents the number of sides a square has. It's a truism, and as such not transient or variable, its a constant value, if it changed when the code was running we might not get a square anymore in the app or program. Other things we represent are things in the code that we just want to make sure don't change when the between the start of the program and the end. I might want to create 5 instances of a class on the heap, and as such at a point in the program I might want to delete that memory, so to make sure I don't have a leak, I want that value to remain constant.
Const Functions
In C++ functions can be marked const. This means that the this pointer (the pointer that is pointing to the instance the current function is on), is not allowed to change anything. A const function can only call other const functions, and as such its a good way to write an accessor function like GetNumberOfDogs. Let's look at the syntax :
int MyClass::GetNumberOfDogs() const {}
So the const keyword follows the rest of the signature of the function.
Java does not support const functions and therefore c# does not support const functions either , so that's an easy comparison !
Const Variables
The real content of this article is the comparison of variables, oh the ironic name here, in our case today we don't want them to vary at all !
C++ constant variables (Oxymoron !)
So lets start with C++. The constness of an attribute or local variable is the quality that renders it immutable. Throughout the program we can not change the value. The syntax is simple, place the keyword const either before or after the type :
int const NumberOfOtherSides = 4;
const int NumberOfSides = 4;
MyClass const myConstInstance;
const MyClass myConstInstance;
The const keyword is for the compiler. So at compile time all const things are checked to make sure either a const function is only calling another const function, there are no assignments to a const variable/attribute, there are no functions being called on that are not const, and there is nothing that is implicitly casting a const to a non-const ie function argument type of reference.
Note that we can pass const things into functions as non const arguments, as they are copies (we pass by copy in C++), unless of course you use a reference as the argument type, in which case the compiler will stop you implicitly casting to a non const reference, here is an overview :
class MyClass
{
public:
void PrintMe()
{
}
void PrintMeOK() const
{
}
};
void okToCall(MyClass copyOfMyInstance)
{
}
void Print(MyClass &myPassedInNonReference) const
{
}
const MyClass myConstInstance;
myConstInstance.PrintMeOK();
okToCall(myConstInstance);
myConstInstance.PrintMe();
Print(myConstInstance);
Great, however those pesky C++'ians, they gave us the Get Of Jail Free card soon enough when they realised that if, and I say if, you did want to change a const variable, then there should be an emergency way to do it. Hence the const cast. You might be getting your product ready to release, and at the last moment need to call a function that you know doesn't change anything in the this instance, but it is not const. You don't want to un-const your instance, and you don't want to strip off the constness of the function, and the function it cals, and the function it calls etc.
I guess this is why C++ succeed, it allows you to change things at the last minute to allow you to get the product out the door. It's a double-edged sword of course, as this philosophy also let's you abuse it and write awful code from day one (if you don't know what you are doing of course).
The const cast is a way of stripping off the constness of a variable, and it looks like this :
nonConstVar = const_cast<type>(OriginalConstVar);
For built in types we can not use the const cast. So for example :
const int myConst = 99;
int myNonConst = const_cast<int> (myConst);
++myConst;
++myNonConst;
The compiler will complain about not only trying to change the const with the pre-increment operator, but also the fact that you can't use const cast with an int.
We can not strip the constness with an instance to another via copying at the same time, so this will not work either :
MyClass const myInstance;
MyClass nonConstInstance = const_cast<MyClass>(myInstance);
But we can strip off the constant with a pointer or a reference :
MyClass const myInstance;
MyClass &nonConstInstance2 = myInstance;
MyClass &nonConstInstance = const_cast<MyClass&>(myInstance);
You can with C++ allow something to be mutable. This means that even if the instance of that class is declared const, you can still change the parts marked with the aforementioned keyword.
class MyClass
{
public:
mutable int NumberOfSides;
};
Now the tricky to explain part. In C++ you can have a pointer, and it can either be const itself, ie if will always hold the same address, or it can be holding an address of a const variable. Or it can be BOTH !
const MyClass* myInstance;
MyClass *const myInstance;
const MyClass* const myInstance;
Here is an example of not being able to modify a constant pointer :
class MyClass
{
private:
int NumberOfSides;
public:
MyClass(int d)
{
NumberOfSides = d;
}
void Print() const
{
cout<<"Number of sides"<<NumberOfSides<<endl;
}
};
int main()
{
MyClass* myar[2];
myar[0] = new MyClass(1);
myar[1] = new MyClass(2);
MyClass* indxor = myar[0];
indxor->Print();
indxor = myar[1];
indxor->Print();
const MyClass* indxorConst = myar[0];
indxorConst->Print();
indxorConst = myar[1];
indxor->Print();
MyClass* const constIndxor = myar[0];
constIndxor = myar[1];
constIndxor->Print();
}
You guessed it we can combine them all :
const MyClass* const MyHellOfAConstFunction(const char* const Name) const
{
}
Ok that's enough c++, I'm feeling dizzy.
C# Const Variables (Oxymoron again !)
In C# a constant variable, is just not that. The end. Only kidding. We can only set the value of a constant attribute of a class when it is declared. So we can do this :
public const int c1 = 5;
And that's it for the lifetime of the program. You can not have a static version of this, as the run time only generates one of them for all instances to share anyway (what would be the point of one for each instance ?). Also you can only have a const of a value type, so no constant instances of reference types like classes, with the exception of string (as this is guaranteed to be immutable). It has to be like this as there are no const functions, so how could the run time stop you calling a function that would change the instance ? It wouldn't know which functions do and which don't, so your constant instance could be changed.
You must design a constant class if you want one, simply don't provide any functions that allow mutability, so no set functions in your accessors, or other functions that change any attributes.
If you want more flexibility that static binding at compile time, use the readonly keyword instead. It will allow you to set the value right up until the class has finished being instantiated, in other words you can change it at declaration or during the constructor, so you could have different values based on which constructor was called. This does allow a limited context of the attribute.
Java Const Variables (Last Oxymoron I promise !)
In Java there are variables that defy their moniker also, and don't allow themselves to change, these are specified with the final keyword :
<code>final int NUMBER_OF_SIDES_TRIANGLE = 3;
NUMBER_OF_SIDES_TRIANGLE = 5;</code>
So we would get a compile error here because we are trying to assign to a final.
The difference between C# and Java is the fact you have to declare the variable static if that's what you want, it's not prohibited in the language like it is in C#.
If you use the final keyword with an instance of an object, then you are saying that you want that reference to be pointing to that instance forever.
If you noticed the keyword const as a reserved keyword in Java then well done. But don't worry it is not used at all.
And that's it. It feels like it was a C++ heavy article, but it clears up what you can and can not do in a single place.
Thanks.
Marcus.