For years the development scene has been dominated by the C family of languages, primarily C itself and its immediate successor C++. Recent years have given rise to other C-descendents, however, such as Sun’s Java and Microsoft’s C#.
Nowadays we here lots of hype about .NET and J2EE, lots of propaganda about how both C# and Java are "The Way of the Future." But as we all know, sometimes the real gem is the unsong underdog, the one that don’t have full page ads in tech journals. And today I’m going to take a look at one such gem: The D Programming Language.
What is D?
D is a (relatively) new addition to the C family of programming languages, intended as a successor to C++ but also incorporating ideas and improvements from other C-like languages such as Java and C#. It is an object-oriented, garbage-collected, systems programming language that is compiled to executable rather than bytecode. The specification and reference compiler are currently at version 0.82, and are expected to reach 1.0 within the year. The reference compiler runs on both Windows and Linux x86, and the frontend if Open-Sourced. A port of the frontend to GCC is underway and already functional on Linux x86 and Mac OS X.
Maintained by Walter Bright, author of the Digital Mars C/C++ compilers and former compiler programmer for both Zorland and Symantec, is the language’s primary author and maintains the reference implementation, though most if not all language decisions are made only after discussion on the D newsgroup. (See links at the end.)
How’s That Different Than What We Had Before?
D is designed to address the shortcomings of C++. While a powerful language, years of history and unneeded complexity has bogged down that language. Five years after the language’s standardization, most compilers are still struggling to become compliant. While C++ pioneered in generic programming and brought objects to the masses, its complexity makes it very hard to add new features, and so it lags behind in newer techniques such as design-by-contract, unit-testing, and include dependency resolution.
In most respects, however, D functions like C++: most C++ code can be converted directly and will, generally speaking, function as expected. Perhaps the largest change in D is the addition of automatic garbage collection, though explicit delete statements will still function as they do in C++.
While not the direct parent of D, many of Java’s techniques have been incorporated into it. Some claim that D’s object definition syntax is more similar to Java’s, though it really ought to be familiar to any modern object-oriented programmer.
In terms of similarities, D and Java are both garbage-collected, both do not make a distinction between the ".", "->", and "::" operators, both include null as a keyword, and both feature try-catch-finally exception handling. Also D’s module system of includes is similar to Java’s packages. As to differences, D is compiled to an executable instead of bytecode, and is not as rigidly object-oriented. Unlike Java, D does not force the object-oriented paradigm on the programmer and can be used just like procedural C. Finally, D allows (but does not encourage) pointer manipulation.
C# and D are really both answers to the same basic question: How can we improve C++? Both are derived from C++ with specific elements drawn in from Java. Both share most of their major features. The biggest difference is that unlike C#, D does not run inside a VM, and can thus be used to write systems (low-level) code. This also allows D to offer the programmer the options of performing manual memory management, which C# does not, nor does C# have anything like D’s templating capabilities, which are on par with C++’s.
OK, What Does It Do?
Having now established what D is not, it might serve us well to note what D is, and to examine some of its features:
Binary C Compatibility
D programs can import and link against C code and libraries, providing D with free access to a huge amount of pre-written code. Note, however, that D is not link-compatible with C++, so pure C wrappers are required to access C++ code in D.
Because D is compiled to binary rather than bytecode, and it does not run inside a virtual machine, D can be used for systems and low-level programming. It allows in-line assembly, and the garbage collector can be regulated (or even disabled) if real-time capabilities are necessary.
Lexicial, Syntactic, and Semantic Clarity
One of the major goals of D is to eliminate a lot of the complexity of C++ that has made it so hard for compilers to live up to the standard. A simplified syntax makes the job of both the compiler and the programmer easier, as it allows compilers to be more efficient and reduces the likelihood of compiler bugs. As an example, D drops the much-contested angular bracket syntax for declaring templates, making code easier both to read and parse.
Design-by-Contract and Automatic Testing
D advocates the use of design-by-contract and provides built-in facilities for automatic unit-testing. While both are technically possible in C++, D makes them core tenets of the language to make them easier to use for novices. The hope is that with testing built into the language bugs will be easier to identify and fix, especially if programmers get into the habit of using the testing features.
Removal of Archaic Features
Probably the language’s greatest goal is the elimination of archaic and/or needlessly complicated features. For instance, D does away completely with the C preprocessor, relying instead on built-in versioning capabilities. Forward declarations are out the window on the same token. Also, it replaces the often-complicated multiple inheritance of C++ with Java’s single inheritance and interfaces. Most of these features are also related with the above of clarity, making the code easier for a human to read as well as easier for a compiler to convert into binary.
These are by no means the only features of D, but for the sake of brevity I shall leave the exploration of the others as an exercise for the reader. For more information, see Walter’s SDWest paper.
So What Does It Look Like?
<pre> //Copyright Walter Bright. Used with permission.
int main (char args)
printf(" lines words bytes file\n");
foreach (char arg; args[1 .. args.length])
int w_cnt, l_cnt, c_cnt;
input = cast(char)std.file.read(arg);
for (int j = 0; j < input.length; j++)
c = input[j];
if (c == '\n')
if (c >= '0' && c <= '9')
else if (c >= 'a' && c <= 'z' ||
c >= 'A' && c <= 'Z')
wstart = j;
inword = 1;
else if (inword)
char word = input[wstart .. j];
inword = 0;
char w = input[wstart .. input.length];
printf("%8lu%8lu%8lu %.*s\n", l_cnt, w_cnt, c_cnt, arg);
l_total += l_cnt;
w_total += w_cnt;
c_total += c_cnt;
if (args.length > 2)
l_total, w_total, c_total);
foreach (char word1; dictionary.keys.sort)
printf("%3d %.*s\n", dictionary[word1], word1);
This program should look familiar to most C/C++ programmers: it’s the classic "word count" program. While most of it should be easily comprehensible to anyone versed in C-like languages, I will highlight a few features:
<pre> import std.c.stdio;
These lines are D’s version of includes. The first imports the plain C stdio functions (notably printf), while the second imports the D standard library (known as Phobos) file I/O systems.
<pre> int main (char args)</pre>
You’ll notice here and throughout the program that D uses neither char* nor a string class for string values. D arrays are "smart arrays," which know their own length and are capable of most of the functionality of C++’s various STL array types.
<pre> int[char] dictionary;</pre>
This declaration will look odd to C++ programmers, but it is in fact a familiar concept: it creates an array of integers that is indexed by strings, called an associative array. This is equivalent to Maps in both STL and JFC, but in D it is a core language feature rather than part of the standard library.
<pre> foreach (char arg; args[1 .. args.length])</pre>
This line illustrates two new features of D:
foreach and slicing.
foreach replaces the need for iterators, as
arg will take on the value of each element in the array as the loop executes. This is guaranteed to be in order if using a standard array, but no order guarantee is made for associative arrays. Slicing is the ability to declare an array as a subarray of another. In this case,
args[1 .. args.length] is the subarray of args that includes all elements except the first. You can also note here that args, an array, knows its own length.
<pre> foreach (char word1; dictionary.keys.sort)</pre>
Any array of entities that defines a comparison operator is sortable, such as the array of keys of an associative array. Again, this is a language feature rather than part of the standard library.
Beyond This Article
This article does not even begin to examine all the features of D. For instance, the above example program does not make use of any of D’s object-oriented features, nor its generic programming capabilities, nor its built-in testing facilities. While all are certainly worthy of note, covering all in one article would be over-ambitious. Instead, here is a list of references where more information about D can be found:
The D Specification (Working Version)
The D Compiler (Linux and Windows)
The D Newsgroup (D Language Features Discussion)
The D.gnu Newsgroup (D for GCC Discussion)
The D Frontend for GCC (Work in Progress. Supports Linux and Mac OS X thus far.)
DSource.org (Newly formed host for D projects. Also hosts tutorials.)
D Links (Large list of D sites and libraries)
About the author:
The author, Owen Anderson, is a Computer Science student at Macalester College. He develops for Mac OS X and Linux, and has recently started the Docoa project to bridge D to Objective-C on Mac OS X.
If you would like to see your thoughts or experiences with technology published, please consider writing an article for OSNews.