Declaring constants
Motivation
The C/C++ way of declaring a constant is to either use a preprocessor macro, which is fraught with peril because preprocessor macros are not subject to syntax restrictions, and therefore full of pitfalls for the unwary:
#define MYCONSTANT 1+2
int y = MYCONSTANT;
/* y==3, as expected */
int x = MYCONSTANT*3;
/* Oops, x==7, not 9 as one might expect */
Or, we can declare a const variable that contains the value:
const int MYCONSTANT = 1+2;
int y = MYCONSTANT;
/* y==3, as expected */
int x = MYCONSTANT*3;
/* Better: x==9. */
But this wastes space to store the constant in a variable, when the constant really only needs to be an integer literal.
Usage
In D, we solve the problem by using manifest constants:
enum MyConstant = 1+2;
int y = MyConstant; // y==3
int x = MyConstant*3; // x==9
The declaration of MyConstant is fully subject to D's type restrictions and syntax, and so does not suffer from the "leaky operator" present in the C preprocessor macro version of the constant in the previous section. It also does not incur any runtime storage space, because the compiler treats MyConstant as a compile-time value only. This gives us the best of both worlds.
Furthermore, manifest constants in D are not restricted to integral types alone; we can also use them with strings and arrays:
enum MyString = "This is a string";
enum MyIntArray = [1, 2, 3];
enum MyStringArray = ["abc", "def", "ghi"];
enum MyNestedArray = [
[ 1, 2, 3 ],
[ 2, 4, 6 ],
[ 2, 3, 5, 7, 11 ]
];
writeln(MyString ~ "!"); // prints "This is a string!"
writeln(MyIntArray[1]); // prints 2
writeln(MyNestedArray[2][3]); // prints 5