Difference between revisions of "Declaring constants"

From D Wiki
Jump to: navigation, search
(Created page with "==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 ...")
 
(caveat)
Line 56: Line 56:
 
writeln(MyNestedArray[2][3]);  // prints 5
 
writeln(MyNestedArray[2][3]);  // prints 5
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 +
==Caveats==
 +
 +
Be aware, however, that manifest constants of arrays (including strings) and [[associative array]]s cause the arrays to be duplicated ''every time'' you use them. For example:
 +
 +
<syntaxhighlight lang=D>
 +
enum MyString = "This is a string";
 +
 +
void main()
 +
{
 +
    auto s = MyString;
 +
    auto t = MyString;
 +
    assert(s !is t);
 +
}
 +
</syntaxhighlight>
 +
 +
This causes MyString 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 (especially since strings have immutable content, so it makes little sense to keep duplicating them), you should declare the string as <code>static immutable</code> instead:
 +
 +
<syntaxhighlight lang=D>
 +
static immutable MyString = "This is a string";
 +
 +
void main()
 +
{
 +
    auto s = MyString;
 +
    auto t = MyString;
 +
    assert(s is t);
 +
}
 +
</syntaxhighlight>
 +
 +
This way, assigning MyString to a variable merely aliases the same one string, rather than allocate a new copy each time.

Revision as of 23:13, 8 August 2013

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

Caveats

Be aware, however, that manifest constants of arrays (including strings) and associative arrays cause the arrays to be duplicated every time you use them. For example:

enum MyString = "This is a string";

void main()
{
    auto s = MyString;
    auto t = MyString;
    assert(s !is t);
}

This causes MyString 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 (especially since strings have immutable content, so it makes little sense to keep duplicating them), you should declare the string as static immutable instead:

static immutable MyString = "This is a string";

void main()
{
    auto s = MyString;
    auto t = MyString;
    assert(s is t);
}

This way, assigning MyString to a variable merely aliases the same one string, rather than allocate a new copy each time.