Meta Programming

From safe to powerful.

Templates

D features templates like C++. They provide a good foundation for generic programming.

For Java programmers, the semantics are subtely different, because a generic function is not compiled to a single function in the binary. Instead it is instantiated multiple times for different arguments. This allows the compiler to optimize each instance specifically, but produces more code.

Traits

D provides a wealth of convenience functions for meta programming called traits. Some come from the compiler and some from the standard library.

String Mixins

The most powerful mechanism for compile-time programming are string mixins. Since D can evaluate functions at compile time, you can generate strings at compile time. A string mixin includes a generate string into source code for further compilation.

template GenStruct(string Name, string M1)
{
  const char[] GenStruct =
    "struct " ~ Name ~ "{ int " ~ M1 ~ "; }";
}

mixin(GenStruct!("Foo", "bar"));

This generates (or is equivalent to) the following.

struct Foo { int bar; }

An advanced example of such meta programming would be the Pegged parser generator. You can provide a grammar and at compile time an efficient parser is generated.

mixin(grammar(`
  Arithmetic:
  Term     < Factor (Add / Sub)*
  Add      < "+" Factor
  Sub      < "-" Factor
  Factor   < Primary (Mul / Div)*
  Mul      < "*" Primary
  Div      < "/" Primary
  Primary  < Parens / Neg / Pos / Number / Variable
  Parens   < "(" Term ")"
  Neg      < "-" Primary
  Pos      < "+" Primary
  Number   < ~([0-9]+)

  Variable <- identifier
`));

The little brother of grammars are regular expressions. The D standard library comes with std.regex, which is also a nice example of meta programming. It turns terse regular expression into code at compile time.

Another great example of meta programming is LuaD. It integrates the Lua scripting language into D. In contrast to the C interface, the Lua stack operations are hidden with meta programming. Effectively, Lua objects can be used like D objects instead of explicit push/pop calls.

auto print = lua.get!LuaFunction("print");
print("Hello, world!");