The D Programming Language

Familiarize yourself with the powerful compiled and managed language D.

During the past few decades, programming languages have come a long way. In comparison to the dawn of UNIX and C, when compiled languages were just getting their start, today's world is full of languages with all sorts of goals and features. In this article, I discuss one such language, D from Digital Mars. D is a natively compiled, statically typed, multiparadigm C-like language. Its aim is to simplify development of any type of application—from kernels to games—by combining the performance and flexibility of C with the productivity-boosting factors of languages, such as Ruby and Python. It originally was conceived by Walter Bright, the man who wrote the first ANSI C++ compiler for DOS. The reference compiler is freely downloadable for both Windows and Linux, and the front end is licensed under a dual GPL and Artistic license.

GDC is a D compiler, which uses the GCC back end and is distributed under the GPL. D's features include the lack of a preprocessor, a garbage collector, flexible first-class arrays, contracts, inline assembler and more. With all this, it still maintains ABI compatibility with C, allowing you to use all your old C libraries from D easily, with little work. The D standard library includes bindings to all standard C functions as well.

Hello World

In D, the Hello World program goes like this:

import std.stdio;  // standard i/o module
int main(char[][] args)
      writefln("Hello world!");
      return 0;

writef is D's typesafe version of printf; writefln adds a newline character at the end. Garbage collector D includes an automatic garbage collector, relieving the programmer of the need to manage memory explicitly. This allows programmers to focus more on the task at hand, as opposed to having to worry about the condition of each memory chunk. Furthermore, it eliminates a whole class of bugs dealing with dangling pointers and invalid memory references. In times when the GC would slow the application down, there is always the option of turning it off altogether or using C's malloc and free for memory management.


In D, modules are imported using the import statement and have a one-to-one correspondence with source files, with the period as the path separator. Each symbol within a module has two names: the name of the symbol and the name of the symbol prefixed by the module name, which is called the fully qualified name or FQN. For example, writefln can be referred to as writefln or std.stdio.writefln. For cases when the FQN is preferred, the static import statement imports the module's symbols but avoids putting them into the global namespace. For example, both the std.string and std.regexp modules include functions for find, replace and split. Because I'm more likely to use pure string functions than regular expressions, I would statically import std.regexp, so that whenever I wanted to use any of its functions, I would have to be explicit, whereas I simply could call the string functions by their regular names.

Modules can have static constructors and destructors. The static this() function in any module is the static constructor and is invoked before main(); after main has returned the static, ~this() function is invoked. Because modules are imported symbolically, this means there are no header files. Everything is declared once and only once, eliminating the need for declaring functions in advance or declaring classes in two places and trying to keep both declarations consistent.

alias and typedef

In D, there is a distinction made between an alias and a type. A typedef introduces an entirely new type to the type-checking system and to function overloading, which are discussed later. An alias is a simple replacement for a type, or optionally a symbol:

alias int size_t;
typedef int myint; //can't implicitly convert to int
alias someReallyLongFunctionName func;

In D, arrays are first-class types in every way. D contains three types of arrays: static, dynamic and associative arrays. Array declarations read right to left; char[][] is interpreted as an array of arrays of characters:

int[] intArray; // dynamic array of ints
int[2][4] matrix; // a 2x4 matrix

All arrays have length, sort and reverse properties. Associative arrays are arrays where the index is something other than sequential integers, possibly text strings, structs or arbitrary integers:

import std.stdio;
int main(char[][] args)
        int[char[]] petNumber;
        petNumber["Dog"] = 212;
        petNumber["cat"] = 23149;
        int[] sortMe = [2, 9, 341, 23, 74, 112349];
        int[] sorted = sortMe.sort;
        int[] reversed = sorted.reverse;
        return 0;

Dynamic and static arrays can be sliced with the .. operator. The starting parameter is inclusive, but the ending parameter is not. Therefore, if you slice from zero to the length of an array, you get the whole array:

int[] numbers = [1, 2, 3, 4, 5, 6, 7];
numbers = numbers[0..2] // 1-3 now

Finally, D uses the ~ operator for concatenation, as addition and concatenation are at their most fundamental two different concepts:

char[] string1 = "Hello ";
char[] string2 = "world!";
char[] string = string1 ~ string2; // Hello world!

This is a prime example of how D implements a lot of syntactic sugar on top of more low-level routines to make the programmer more focused on the implementation of the task itself. Strings D takes arrays one step further. Because strings are logically arrays of characters, D has no built-in string type; instead we simply declare an array of characters.

Furthermore, D has three types of strings: char, a UTF-8 codepoint; wchar, a UTF-16 codepoint; and dchar, a UTF-32 codepoint. These types, along with standard library routines for manipulating unicode characters, make D a language suited to internationalized programming. In comparison with C, D strings know their length, eliminating even more bugs and security issues dealing with finding the elusive null terminator.



Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

What a badly designed language

rae's picture

I can't see any better than C/C++ or Python.

the "~" concatenating operator is ugly than any other language,

the gc makes it not a pure compiling language.

It's pure compiling

Anonymous's picture

It's pure compiling language! "~" is used becouse, "+" means addition, not concatenating. You can find rational arguments for this and other problems on D web page.

BTW. "inout" parameters are now renamed to "ref".

As of 1.011

Anonymous's picture

"BTW. 'inout' parameters are now renamed to 'ref'."

As of 1.011

Funny though, its badly designed because it uses ~ and has gc. And I wonder what pure compiling means if gc makes this no longer true?

Why makes gc pure compiling no longer true

Anonymous's picture

Why makes gc pure compiling (whatever that means) no longer true ? GC is done by the runtime and has nothing to do with compiling. D is a "pure compiling" language (as pure as you can get - there is nothing more pure than compiling into platform dependent native code). And why is a language badly designed just because it has the option to use garbage collection (in D you can manage memory by yourself and turn garbage collection completely off, if you want to) ?

Using ~ for concatenating arrays and not + makes sense because your not adding strings like you are adding numbers. But that might be just a matter of taste.

But if these two things are the only criterions for you to decide if a language is good or bad designed, you should better not become a language designer.

Improvements over C++

Anonymous's picture

For a (not complete) list of things which are "improvements" over C++ just take a look at

As always this is a matter of taste and personal preference. But C++ had to be designed to be backward compatible to C, so some things could not be as clean designed as they should be and make the language more complicated and error prone.