Since several weeks, I gave a second look at the D programming language after watching videos of talk gave by Andrei Alexandrescu and Walter Bright at Lang.NEXT conference (see Walter video and Andrei video). I decided to explain my favorite and cool features of the language. Of course there’s many more, I invite you to take a look at the website to find more information about the language.

scope guard statement

scope guard statement allows you to write code that will be executed either at the exit of the function, when the function succeeds (when they are no error or expection raised) and when you get failure by error or an exception.

It can be used to simulate the RAII pattern. Say you need to write data coming from a database into a File and the API isn’t RAII friendly. You could use try-catch-finally statements like this

auto file = new std.stream.File("test.txt", FileMode.In); auto db = new SqlDatabase(); try { db.open(); } catch(SqlException e) { writeln(e); return; } try { db.callFunctionThatFails(file); } catch(SqlException e) { writeln(e); } finally { db.close(); file.close(); }

It’s a simple code with some flaws (the File object is never closed).If we nest various try-catch statement, code can become pretty cluttered and hard to read. Here’s the version with the scope(exit) statement

auto file = new std.stream.File("test.txt", FileMode.In); auto db = new SqlDatabase(); scope(exit) { file.close(); db.close(); } try { db.open(); db.callFunctionThatFails(file); } catch(SqlException e) { writeln(e); }

Behind the scene, the compiler will write the correct try-catch statement for you.

The other scope guard are scope(success) and scope(failure). Here’s I created a small testcase with throw an exception every multiple of 3. It prints “Everything under control” and return 2 when there’s no exception and print “Just a flesh wound !” and return 5 when an exception is thrown.

import std.stdio; int globalCounter = 0; void functionThatThrowRandomly() { globalCounter++; globalCounter = globalCounter % 3; if(globalCounter == 0) { throw new Exception("Forced exception"); } } int test() { scope(success) { writeln("Everything under control."); } scope(failure) { writeln("Just a flesh wound !"); return 5; } functionThatThrowRandomly(); return 2; } void main(string[] argv) { foreach(i; 0..20) { writeln("Iteration ", i); int value = test(); writeln("Value: ", value); } readln(); }

Here’s the output of this code:

Iteration 0 Everything under control. Value: 2 Iteration 1 Everything under control. Value: 2 Iteration 2 Just a flesh wound ! Everything under control. Value: 5 Iteration 3 Everything under control. Value: 2 Iteration 4 Everything under control. Value: 2 Iteration 5 Just a flesh wound ! Everything under control. Value: 5 Iteration 6 Everything under control. Value: 2 Iteration 7 Everything under control. Value: 2 Iteration 8 Just a flesh wound ! Everything under control. Value: 5 Iteration 9 Everything under control. Value: 2 Iteration 10 Everything under control. Value: 2 Iteration 11 Just a flesh wound ! Everything under control. Value: 5 Iteration 12 Everything under control. Value: 2 Iteration 13 Everything under control. Value: 2 Iteration 14 Just a flesh wound ! Everything under control. Value: 5 Iteration 15 Everything under control. Value: 2 Iteration 16 Everything under control. Value: 2 Iteration 17 Just a flesh wound ! Everything under control. Value: 5 Iteration 18 Everything under control. Value: 2 Iteration 19 Everything under control. Value: 2

More information about scope guard statement

templates and static if

D is influenced by C++ and contains similar features. One of the most powerful and confusing feature in C++ is template. Templates in C++ are used to create generic containers, algorithms, metaprogramming, compile-time type identification using traits and much more. If you are doing only generic container and algorithm, template are intuitive. But as soon you start doing metaprogramming, templates in C++ become a real clusterfuck.

In C++, to do a template that selects between two types according to a boolean expression looks like this (taken from Andrei’s book Modern C++ design)

template<bool flag, typename T, typename U> struct Select { typedef T Result; }; template<typename T, typename U> struct Select<false, T, U> { typedef U Result; }; template<typename T, bool isPolymorphic> class NitfyContainer { typedef typename Select<isPolymorphic,T*,T>::Result ValueType; ValueType m_value; }

In D, using template declaration and static if, the same template looks like this

template Select(bool condition, T, F) { static if (condition) alias T Select; else alias F Select; } class NitfyContainer(T,bool isPolymorphic) { alias Select!(isPolymorphic,T*,T) ValueType; ValueType m_value; }

First thing you notice is that D does not use the angular bracket for template like C++, Java and C#. In C++, if you are using a C++03 compiler, type like map<string,Vector<int>> will confuse the compiler on >>, because it can’t decide if it’s a template or the shift right operator. (This problem was fixed in the C++11 standard). In D, they designed the language to be easy to comprehend by a tool with no or little semantic analysis as possible.

Another neat thing about template in D is if the variable inside the template has the same name as the template, you don’t need to access it, the compiler will use the value directly, as you can see in the Select example.

Variadic template are also supported (template that accepts arbitrary number of arguments)

template SelectFirstOrLast(bool selectFirst, Ts...) { static if(selectFirst) { enum SelectFirstOrLast = Ts[0]; } else { enum SelectFirstOrLast = Ts[$ -1]; } } void test() { auto firstItem = SelectFirstOrLast!(true,1,2,3,4,5); auto lastItem = SelectFirstOrLast!(false,1,2,3,4,5); // firstItem is 1 // lastItem is 5 }

Variadic argument are accessed like an array: you can use the length of the array shortcut (the dollar sign), you can use slices and so on. Notice also the use of enum. In D, enum can be a compile-time constant of any type. It is not limited only to integer and the compiler can infer the type from the context.

More information about templates

More information about static if

Compile time function execution

D allows function to be called at compile time. Of course they are restrictions:

The function source code must be available to the compiler. Executed expressions can’t reference global or local static variable Cannot call assembly code Non-portable cast C-style pointer arithmetic Non-recoverable errors (such as assert failures)

For functions to be evaluated at compile time, you must store the result of your function in a static variable, a const variable or an enum variable.

Here’s an example from Wikipedia that generate factorials into an array at compile-time

int[] genFactorials(int n) { auto result = new int[n]; result[0] = 1; foreach (i; 1 .. n) result[i] = result[i - 1] * i; return result; } enum factorials = genFactorials(13); // 'factorials' contains at compile-time: // [1, 1, 2, 6, 24, 120, 720, 5_040, 40_320, 362_880, 3_628_800, // 39_916_800, 479_001_600]

More info about compile-time function execution

mixin

mixin is like eval in most of the dynamic languages (Javascript, Python, Ruby), it takes a string literal and compile it to D.

void main(string[] args) { mixin("auto x = 3.1415;"); writeln("PI generated by mixin: ", x); }

But as you learned in the last section, you can execute code at compile-time, including string concatenation. It opens many possibilities for code generation.

Philippe Sigaud’s Pegged, a parsing expression grammar (PEG) generator, is the quintessential example of mixin power. You define the grammar in a string literal

import pegged.grammar; mixin(grammar(` Arithmetic: Expr < Factor AddExpr* AddExpr < ^('+'/'-') Factor Factor < Primary MulExpr* MulExpr < ^('*'/'/') Primary Primary < '(' Expr ')' / Number / Variable / ^'-' Primary Number Variable `));

Behind the scene, the grammar() template generated classes for each rule of the grammar. Here’s how to use the generated code by grammar()

// Parsing at compile-time: enum parseTree1 = Expr.parse("1 + 2 - (3*x-5)*6"); pragma(msg, parseTree1.capture); assert(parseTree1.capture == ["1"d, "+"d, "2"d, "-"d, "("d, "3"d, "*"d, "x"d, "-"d, "5"d, ")"d, "*"d, "6"d]); writeln(parseTree1); // And at runtime too: auto parseTree2 = Expr.parse(" 0 + 123 - 456 "); assert(parseTree2.capture == ["0"d, "+"d, "123"d, "-"d, "456"d]);

In my experiment with D, I was able to generate serialization code using templates, mixin, compile-time function execution and compile-time reflection. Here’s the full source code of that experiment, it doesn’t compile on ideone.com because the DMD compiler is too old.

More information about mixin

Uniform function call syntax

UFCS (as it’s called by the community) is a newest addition of the language that unifies the calling syntax. It allows free functions (functions outside classes) that take a class as a first parameter to be called like it was a member of that class, similar to extension methods in C#. It’s ease the pain while using non-member functions to increase encapsulation, an idiom suggested by Scott Meyer in Effective C++.

Let’s say you don’t want your serialization code to clutter your class or struct definition, you could do something like this:

class MyClass { // some fields and method } void serialize(MyClass p, JSONSerializer serializer) { serializer.writeString(p.stringField); // etc... } void main() { auto data = new MyClass(); auto jsonWriter = new JSONSerializer(); serialize(data, jsonWriter); }

Without UFCS, you need to pass explicitly MyClass instance to serialize. But with UFCS, you can do instead.

data.serialize(jsonWriter);

The downside of UFCS is that it is harder to tell if the method is defined inside the class or if it’s a free function.

More information about UFCS

with

with is a simple statement inspired by Pascal and Visual Basic that simplify repeated calls or access to an object. It’s a nice feature to have when you interact with C code like the Win32 API which require lots of fields initialization.

Here’s a C code that register a window class in Win32

WNDCLASSEX wcex; wcex.cbSize = sizeof( WNDCLASSEX ); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon( hInstance, ( LPCTSTR )IDI_TUTORIAL1 ); wcex.hCursor = LoadCursor( NULL, IDC_ARROW ); wcex.hbrBackground = ( HBRUSH )( COLOR_WINDOW + 1 ); wcex.lpszMenuName = NULL; wcex.lpszClassName = L"TutorialWindowClass"; wcex.hIconSm = LoadIcon( wcex.hInstance, ( LPCTSTR )IDI_TUTORIAL1 ); if( !RegisterClassEx( &wcex ) ) return E_FAIL;

And here’s the same block in D using the with statement

WNDCLASSEX wcex; with(wcex) { style = CS_HREDRAW | CS_VREDRAW; lpfnWndProc = &WndProc; cbClsExtra = 0; cbWndExtra = 0; hInstance = p_hInstance; hIcon = LoadIcon(p_hInstance, cast(const char*)IDI_TUTORIAL1); hCursor = LoadCursor(NULL, IDC_ARROW); hbrBackground = cast(HBRUSH)(COLOR_WINDOW+1); lpszMenuName = ""; lpszClassName = "TutorialWindowClass"; hIconSm = LoadIcon(p_hInstance, cast(const char*)IDI_TUTORIAL1); }

Note that to remove ambiguity, I renamed hInstance parameter to p_hInstance.

More information about with statement

Conclusion

The D language is powerful and deep and they are many things to learn about this language. For go further, I suggest you read the official documentation on the website and to read Andrei’s book The D Programming Language. As for me, I think I’ve finally found a worthy successor of C++ for my projects that required C++ in the past. I’m currently investigating doing DirectX 11 code using D.