2.9.2 Associative Arrays

Associative arrays are used to represent collections of data elements that can be retrieved by specifying a name, which is called a key. D associative array keys are formed by a list of scalar expression values, called a tuple. You can think of the array tuple as an imaginary parameter list to a function that is called to retrieve the corresponding array value when you reference the array. Each D associative array has a fixed key signature consisting of a fixed number of tuple elements, where each element has a given, fixed type. You can define different key signatures for each array in your D program.

Associative arrays differ from normal, fixed-size arrays in that they have no predefined limit on the number of elements: the elements can be indexed by any tuple, as opposed to just using integers as keys, and the elements are not stored in preallocated, consecutive storage locations. Associative arrays are useful in situations where you would use a hash table or other simple dictionary data structure in a C, C++, or Java language program. Associative arrays provide the ability to create a dynamic history of events and state captured in your D program, which you can use to create more complex control flows.

To define an associative array, you write an assignment expression of the following form:

name [ key ] = expression ;

where name is any valid D identifier and key is a comma-separated list of one or more expressions.

For example, the following statement defines an associative array a with key signature [ int, string ] and stores the integer value 456 in a location named by the tuple [123, "hello"]:

a[123, "hello"] = 456;

The type of each object that is contained in the array is also fixed for all elements in a given array. Because it was first assigned by using the integer 456, every subsequent value that is stored in the array will also be of type int. You can use any of the assignment operators that are defined in Section 2.8, “Types, Operators, and Expressions” to modify associative array elements, subject to the operand rules defined for each operator. The D compiler produces an appropriate error message if you attempt an incompatible assignment. You can use any type with an associative array key or value that can be used with a scalar variable.

You can reference an associative array by using any tuple that is compatible with the array key signature. The rules for tuple compatibility are similar to those for function calls and variable assignments. That is, the tuple must be of the same length and each type in the list of actual parameters and must be compatible with the corresponding type in the formal key signature. For example, for an associative array x that is defined as follows:

x[123ull] = 0;

The key signature is of type unsigned long long and the values are of type int. This array can also be referenced by using the expression x['a'] because the tuple consisting of the character constant 'a', of type int and length one, is compatible with the key signature unsigned long long, according to the arithmetic conversion rules. These rules are described in Section 2.8.11, “Type Conversions”.

If you need to explicitly declare a D associative array before using it, you can create a declaration of the array name and key signature outside of the probe clauses in your program source code, for example:

int x[unsigned long long, char];
BEGIN
{
  x[123ull, 'a'] = 456;
}

Storage is allocated only for array elements with a nonzero value.

Note

When an associative array is defined, references to any tuple of a compatible key signature are permitted, even if the tuple in question has not been previously assigned. Accessing an unassigned associative array element is defined to return a zero-filled object. A consequence of this definition is that underlying storage is not allocated for an associative array element until a non-zero value is assigned to that element. Conversely, assigning an associative array element to zero causes DTrace to deallocate the underlying storage.

This behavior is important because the dynamic variable space out of which associative array elements are allocated is finite; if it is exhausted when an allocation is attempted, the allocation fails and an error message indicating a dynamic variable drop is generated. Always assign zero to associative array elements that are no longer in use. See Chapter 10, Options and Tunables for information about techniques that you can use to eliminate dynamic variable drops.