Difference between revisions of "Declaring constants"
(enum of string doesn't allocate a new copy each time.) |
m |
||
(One intermediate revision by the same user not shown) | |||
Line 87: | Line 87: | ||
This way, assigning MyArray to a variable merely aliases the same one array, rather than allocate a new copy each time. | This way, assigning MyArray to a variable merely aliases the same one array, rather than allocate a new copy each time. | ||
− | Note that this doesn't apply to strings, but | + | Note that this doesn't apply to strings, but usages of same manifest constant of string alias the same one string(strings have immutable content, so it makes little sense to keep duplicating them). If you really want to duplicate them, use .dup or .idup. |
<syntaxhighlight lang=D> | <syntaxhighlight lang=D> | ||
enum MyString = "This is a string"; | enum MyString = "This is a string"; |
Latest revision as of 09:22, 2 February 2015
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 7
Caveats
Be aware, however, that manifest constants of arrays(except for strings) and associative arrays cause the arrays to be duplicated every time you use them. For example:
enum MyArray = [1, 2, 3, 4];
void main()
{
auto s = MyArray;
auto t = MyArray;
assert(s !is t);
}
This causes MyArray to be allocated twice at runtime. This is great if you wish to have multiple copies of it; but if you only need a single copy, you should declare the array as static immutable
instead:
static immutable MyArray = [1, 2, 3, 4];
void main()
{
auto s = MyArray;
auto t = MyArray;
assert(s is t);
}
This way, assigning MyArray to a variable merely aliases the same one array, rather than allocate a new copy each time.
Note that this doesn't apply to strings, but usages of same manifest constant of string alias the same one string(strings have immutable content, so it makes little sense to keep duplicating them). If you really want to duplicate them, use .dup or .idup.
enum MyString = "This is a string";
void main()
{
auto s = MyString;
auto t = MyString;
assert(s is t);
}