Difference between revisions of "Declaring constants"
m |
(enum of string doesn't allocate a new copy each time.) |
||
Line 59: | Line 59: | ||
==Caveats== | ==Caveats== | ||
− | Be aware, however, that manifest constants of arrays ( | + | Be aware, however, that manifest constants of arrays(except for strings) and [[associative array]]s cause the arrays to be duplicated ''every time'' you use them. For example: |
<syntaxhighlight lang=D> | <syntaxhighlight lang=D> | ||
− | enum | + | enum MyArray = [1, 2, 3, 4]; |
void main() | void main() | ||
{ | { | ||
− | auto s = | + | auto s = MyArray; |
− | auto t = | + | auto t = MyArray; |
assert(s !is t); | assert(s !is t); | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | This causes | + | 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 <code>static immutable</code> instead: |
+ | |||
+ | <syntaxhighlight lang=D> | ||
+ | static immutable MyArray = [1, 2, 3, 4]; | ||
+ | |||
+ | void main() | ||
+ | { | ||
+ | auto s = MyArray; | ||
+ | auto t = MyArray; | ||
+ | assert(s is t); | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | 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 two usage of a manifest constant aliases the same one string(especially since 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"; | |
void main() | void main() | ||
Line 84: | Line 98: | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | |||
− | |||
[[Category:CommonIdiom]] | [[Category:CommonIdiom]] |
Revision as of 09:15, 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 two usage of a manifest constant aliases the same one string(especially since 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);
}