• 9
• 9
• 11
• 12
• 9
• entries
32
46
• views
126696

# D Arrays

960 views

Every D programmer loves D's arrays. All of them. I challenge you to find one who doesn't. Particularly, it's the ability to slice and manipulate arrays without worrying about memory that really pulls people in.

In my previous post, I talked about Dolce's game screens and the stack-based screen manager. Internally, the stack that the screen manager uses is not a custom-built stack class, nor any sort of container from an existing library. It's an array. You can implement a stack quite easily with a D array.

// Declare an empty dynamic array to use as your stack.Item[] stack;// To push an item onto the stack, use the array append/concat operator.stack ~= something;// To pop, simply decrease the length of the array.stack.length -= 1;// What if we have a queue instead of a stack and want to take the first item?// First, save the item at the head of the queue.auto item = queue[0];// Then reassign the array to a slice of itself, starting from index #1 to the last index. // The $is a substitute for the length property of the array. The first number in a slice// is inclusive, the second exclusive. So the resulting slice below will contain all elements// from queue[1] to queue[queue.length - 1].queue = queue[1 ..$];

D's arrays are quite powerful. In addition to being arrays, they are also ranges, which is something that would take more than a simple post to explain. I don't quite fully grok them myself yet. But, when used in conjunction with the std.algorithm module, there's a great deal of power behind them.

You can read more about D's arrays in this article on slicing in D by Steven Schveighoffer. Also, see the documentation for the std.range module to get an idea of what ranges are.

But wait, there's more! The registry the screen manager uses is a built-in associative array. While there are some more sophisticated hashmap implementations out there for when you really need them, the built-in AAs will cover a lot of your use cases.

// Declare an AA that uses strings as keys.Item[string] registry;// Add an item.registry["foo"] = myItem;// Remove an item.registry.remove("foo");// Test if an item exists in the AA . // The in operator returns a pointer.auto item = key in registry;if(item !is null) // Do something// Efficiently iterate all the values via a delegateforeach(val; registry.byValue()) writeln(val);// Or the keysforeach(key; registry.byKey()) writeln(key);// But don't try to remove anything while iterating the delegates as above. Instead,// iterate over an array of keys or values using the .keys or .values properties.foreach(key; registry.keys){ auto item = registry[key]; if(item.removeMe) registry.remove(key);}

D's arrays and AAs will get you farther than those of C++ or Java. But, when you need more, there is also a range-based container module, std.container, which will eventually hold a number of container types. Also, as an alternative, Steven Schveighoffer's DCollections library is quite awesome.

Nice post.

One thing I really don't like about D's arrays is the fact that array literals are allocated by the GC, even when initialising a static array:

int[3] a = [1, 2, 3]; // performs GC alloc then copies the elements into the array

As far as I can tell, there is no simple (built in) way to initialise a static array without a heap allocation. You either have to do it manually:

// yuck!
int[3] a;
a[0] = 1;
a[1] = 2;
a[2] = 3;

Or I suppose you could write a funky variadic template function for it, but I can't figure out the syntax for that (or even determine if it's possible).

According to some helpful peeps at stackoverflow, you can circumvent the heap alloc by declaring a static const array and then copying it.

static const int[3] data = [1, 2, 3];
int[3] a = data;

data goes in the data segment.