Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Examples of what D’s templates can be used for

Tags:

I hear that the D language has powerful metaprogramming features for executing functions at compile time. That sounds very exciting, but I find it difficult to think of practical examples of things that are hard to accomplish without them.

Can anyone give some examples of situations where D's metaprogramming features comes in very handy?

like image 370
Dimitri C. Avatar asked Aug 24 '10 10:08

Dimitri C.


2 Answers

One really cool and practical usage of compile time function execution is for generating code at compile time, possibly from config files, or maybe scripts.

Here's a simple example of processing a file at compile time.

main.d

string make_ints(string s) {     string ret = "";     foreach (varname; split(s))         ret ~= "int " ~ varname ~ "; ";     return ret; }  void main() {     mixin(make_ints(import("script")));     foo = 1;     bar = 2;     xyz = 3; } 

script

foo bar xyz 

At compile time, the file "script" will be read, split at spaces, and then make_ints returns int foo; int bar; int xyz; directly into the D code, ready for those variables to be used.

While this is a useless example, you could easily see how this could be used to read values from a config file (maybe values for the size of a cache, or something like that). Games could make use of this to generate raw D code from scripts, which will be great for performance (typically games resort to using interpreted code for scripting, and suffer performance wise).

You could also use this for automatic performance tuning. Say you have some constant X, which can be tweaked to affect performance in various ways, but you don't know what value of X will give you the best performance. You could put X in a file, read it in at compile time for use, try some other values at run time and put the best one back into the file. That way, you get gradually improving performance without having to do anything manually.

like image 62
Peter Alexander Avatar answered Oct 22 '22 00:10

Peter Alexander


If you want practical examples of how to use D's metaprogramming facilities (CTFE, or compile time function evaluation, is just one of these, and not even the most important one) look no further than Phobos, the D2 standard library. Much of this code is written by Andrei Alexandrescu, who invented a lot of the template metaprogramming techniques in C++, and is now working with Walter Bright on the design and implementation of D.

The best modules to look in are std.range and std.algorithm. These are almost entirely composed of templates, were designed by Andrei, and are surprisingly readable given the amount of metaprogramming they use. I've contributed significantly to both of these modules and reading the code that was there when I started was basically how I learned.

All of the code is licensed under the (extremely permissive) Boost license and can be viewed directly from your browser at the Phobos Trac site on dsource.org.

To give you a roadmap of what you're looking at, D's metaprogramming facilities basically fall into 4 categories:

  1. Templates, which are basically like C++ templates, but with some added features like static if,static assert, variadic templates, and constraints, which are basically like concepts but simpler.

  2. Compile time reflection/introspection. This includes the builtin is() expressions and __traits, as well as the standard library module std.traits.

  3. Mixins. These allow you to take either a template (template mixins) or a compile time string (string mixins) and evaluate it as code in the current scope. String mixins can be thought of as being kind of like an eval statement, except that the string is evaluated as code at compile time instead of at runtime.

  4. Compile time function evaluation, or CTFE, which allows functions that meet certain criteria to be evaluated at compile time. One important use of CTFE is that, combined with string mixins, you can generate code as a string at compile time, and then evaluate it as code in the scope where the mixin statement occurs. For examples of this, see std.range.Lockstep and std.range.OutputRangeObject, which I recently checked into the SVN releases of Phobos.

like image 20
dsimcha Avatar answered Oct 21 '22 22:10

dsimcha