This Week in D December 13, 2015

Welcome to This Week in D! Each week, we'll summarize what's been going on in the D community and write brief advice columns to help you get the most out of the D Programming Language.

The D Programming Language is a general purpose programming language that offers modern convenience, modeling power, and native efficiency with a familiar C-style syntax.

This Week in D has an RSS feed.

This Week in D is edited by Adam D. Ruppe. Contact me with any questions, comments, or contributions.

Statistics

Major Developments

DConf 2016 news: 20+% sold out and a book signing was announced with Andrei Alexandrescu, author of the book, The D Programming Language, Mike Parker, author of the new Learning D, Ali Çhreli, author of Programming in D, and Kai Nacke, author of D Web Development, all signing their respective books.

See the list of D books here.

A long requested feature, a Testing Nightly Build Service was also released this week.

In the community

Community announcements

See more at the announce forum.

Tip of the Week

If you need to clear an associative array, some people try to assign [] to it, and find it doesn't work. Instead, you can use = null to clear an AA.

On built-in arrays, [] and null are basically the same thing, but [] is typed T[], with T deduced automatically from context or contents, and null has a special type all to itself (which you can reference in your code with typeof(null), which you can overload on, but remember ONLY the null literal has this type). [] can implicitly convert to other array types, and thus, for example, int[] foo = []; works, but it can not convert to associated array types, so int[string] foo = []; does not work.

typeof(null), on the other hand, does implicitly convert to both array and associative array types, so int[string] foo = null; compiles successfully. The implementation does the same thing: it sets the pointer to null ([] also sets it to null to avoid array allocations when just emptying the array) which the runtime will lazily allocation when you actually use it.

typeof(null) will implicitly construct several built-in types, meaning you can pass null to a function expecting int[], for example, but not to any user-defined types. In D today, there is no way to define implicit constructors, meaning a library array type can never fully replace built-in arrays, despite operator overloading making everything else possible. In my personal opinion, the mistake C++ made with its implicit constructors wasn't including them in the language, they do serve a useful purpose, but the mistake they made was making implicit the default, and making explicit the keyword to turn it off. I'd love to see D add explicitly implicit constructors; one of the few language features I still wish for despite being generally quite pleased with D's features.

This lazy allocation, by the way, can be surprising in some cases:

	import std.stdio : writeln;
	void foo(int[string] a) {
		a["something"] = 10;
	}

	void main() {
		int[string] a = null;
		a["else"] = 20;
		foo(a);
		writeln(a);
	}

That program will print ["something":10, "else":20], showing both values got saved in the array.

	// In this example, the printed value will only show
	// ["else":20] in contrast to the previous one, but all
	// I changed, was swapping the order of the function call
	// and the assignment lines!

	import std.stdio : writeln;
	void foo(int[string] a) {
		a["something"] = 10;
	}

	void main() {
		int[string] a = null;
		foo(a);
		a["else"] = 20;
		writeln(a);
	}

The reason for the difference is lazy initialization of the content pointer in the array: in the first case, we set a value before the function call, meaning it was non-null going into it. In the second case, the initialization came after null was already passed to the function foo, meaning it got lazy initialized twice - two separate copies.

I typically advise against passing arrays in D as ref, because the array contents are already passed as reference (the pointer to the contents is passed by value, meaning the contents aren't copied), but this is one case where you might want to use ref. The pointer is modified and ref would pass that up the chain too.

Some people try to avoid this behavior by initializing with = [] instead of = null, but aside from the type mismatch described above, this also doesn't work because [] still keeps a null pointer! You need to actually set a value in the same scope as initialization to get it to allocate a unique pointer.

While [] and null basically do the same thing, a null array and an empty array are still slightly different in D. An empty array can also be the result of a slice at the end of an array: int[] a = [1]; a = a[$ .. $]; /* yields an empty, but non-null array */, whereas a null array is one that is not yet allocated.

I recommend you use the explicit if(arr.length == 0) or if(arr.empty) (import std.array; for the empty function) to test for emptiness, which also includes null arrays, and if(arr is null) if you want to specifically test for null. Only check for null if you are sure that is what you want. Since null arrays will automatically allocate in D, you can get away with never actually worrying about it and just using them as interchangeable with empty arrays. Avoid if(arr), which checks for nullness but is unclear to readers of the code who do not understand the distinctions described here.

Learn more about D

To learn more about D and what's happening in D: