Free Trial

Safari Books Online is a digital library providing on-demand subscription access to thousands of learning resources.


  • Create BookmarkCreate Bookmark
  • Create Note or TagCreate Note or Tag
  • DownloadDownload
  • PrintPrint
Share this Page URL
Help

Foreword by Scott Meyers

Foreword by Scott Meyers

By any measure, C++ has been a tremendous success, but even its most ardent proponents won’t deny that it’s a complicated beast. This complexity influenced the design of C++’s most widely used successors, Java and C#. Both strove to avoid C++’s complexity—to provide most of its functionality in an easier-to-use package.

Complexity reduction took two basic forms. One was elimination of “complicated” language features. C++’s need for manual memory management, for example, was obviated by garbage collection. Templates were deemed to fail the cost/benefit test, so the initial versions of these languages chose to exclude anything akin to C++’s support for generics.

The other form of complexity reduction involved replacing “complicated” C++ features with similar, but less demanding, constructs. C++’s multiple inheritance morphed into single inheritance augmented with interfaces. Current versions of Java and C# support templatesque generics, but they’re simpler than C++’s templates.

These successor languages aspired to far more than simply doing what C++ did with reduced complexity. Both defined virtual machines, added support for runtime reflection, and provided extensive libraries that allow many programmers to shift their focus from creating new code to gluing existing components together. The result can be thought of as C-based “productivity languages.” If you want to quickly create software that more or less corresponds to combinations of existing components—and much software falls into this category—Java and C# are better choices than C++.

But C++ isn’t a productivity language; it’s a systems programming language. It was designed to rival C in its ability to communicate with hardware (e.g., in drivers and embedded systems), to work with C-based libraries and data structures without adaptation (e.g., in legacy systems), to squeeze the last drop of performance out of the hardware it runs on. It’s not really an irony that the performance-critical components of the virtual machines beneath Java and C# are written in C++. The high-performance implementation of virtual machines is a job for a systems language, not a productivity language.

D aims to be C++’s successor in the realm of systems programming. Like Java and C#, D aims to avoid the complexity of C++, and to this end it uses some of the same techniques. Garbage collection is in, manual memory management is out.[1] Single inheritance and interfaces are in, multiple inheritance is out. But then D starts down a path of its own.

[1] Actually, it’s optional. As befits a systems programming language, if you really want to perform manual memory management, D will let you.

It begins by identifying functional holes in C++ and filling them. Current C++ offers no Unicode support, and its nascent successor version (C++0x) provides only a limited amount. D handles Unicode from the get-go. Neither current C++ nor C++0x offers support for modules, Contract Programming, unit testing, or “safe” subsets (where memory errors are impossible). D offers all these things, and it does so without sacrificing the ability to generate high-quality native code.

Where C++ is both powerful and complicated, D aims to be at least as powerful but less complicated. Template metaprogrammers in C++ have demonstrated that compile-time computation is an important technology, but they’ve had to jump through hoops of syntactic fire to practice it. D offers similar capabilities, but without the lexical pain. If you know how to write a function in current C++, you know nothing about how to write the corresponding C++ function that’s evaluated during compilation. If you know how to write a function in D, however, you know exactly how to write its compile-time variant, because the code is the same.

One of the most interesting places where D parts ways with its C++-derived siblings is in its approach to thread-based concurrency. Recognizing that improperly synchronized access to shared data (data races) is a pit that’s both easy to fall into and hard to climb out of, D turns convention on its head: by default, data isn’t shared across threads. As D’s designers point out, given the deep cache hierarchies of modern hardware, memory often isn’t truly shared across cores or processors anyway, so why default to offering developers an abstraction that’s not only an illusion, it’s an illusion known to facilitate the introduction of difficult-to-debug errors?

All these things and more make D a noteworthy point in the C heritage design space, and that is reason enough to read this book. The fact that the author is Andrei Alexandrescu makes the case even stronger. As codesigner of D and an implementer of substantial portions of its library, Andrei knows D like almost no one else. Naturally, he can describe the D programming language, but he can also explain why D is the way it is. Features present in the language are there for a reason, and would-be features that are missing are absent for a reason, too. Andrei is in a unique position to illuminate such reasoning.

This illumination comes through in a uniquely engaging style. In the midst of what might seem to be a needless digression (but is actually a waystation en route to a destination he needs you to reach), Andrei offers reassurance: “I know you are asking yourself what this has to do with compile-time evaluation. It does. Please bear with me.” Regarding the unintuitive nature of linker diagnostics, Andrei observes, “If you forget about --main, don’t worry; the linker will fluently and baroquely remind you of that in its native language, encrypted Klingon.” Even references to other publications get the Alexandrescu touch. You’re not simply referred to Wadler’s “Proofs are programs,” you’re referred to “Wadler’s fascinating monograph ‘Proofs are programs.’” Friedl’s “Mastering regular expressions” isn’t just recommended, it’s “warmly recommended.”

A book about a programming language is filled with sample code, of course, and the code samples also demonstrate that Andrei is anything but a pedestrian author. Here’s his prototype for a search function:

bool find(int[] haystack, int needle);

This is a book by a skilled author describing an interesting programming language. I’m sure you’ll find the read rewarding.

Scott Meyers

January 2010