Difference between revisions of "Declaring constants"

From D Wiki
Jump to: navigation, search
m
m
 
(2 intermediate revisions by the same user not shown)
Line 59: Line 59:
 
==Caveats==
 
==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:
+
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 MyString = "This is a string";
+
enum MyArray = [1, 2, 3, 4];
  
 
void main()
 
void main()
 
{
 
{
     auto s = MyString;
+
     auto s = MyArray;
     auto t = MyString;
+
     auto t = MyArray;
 
     assert(s !is t);
 
     assert(s !is t);
 
}
 
}
 
</syntaxhighlight>
 
</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:
+
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 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>
static immutable MyString = "This is a string";
+
enum MyString = "This is a string";
  
 
void main()
 
void main()
Line 84: Line 98:
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
 
This way, assigning MyString to a variable merely aliases the same one string, rather than allocate a new copy each time.
 
 
[[Category:CommonIdiom]]
 
[[Category:CommonIdiom]]

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);
}