I’ve been playing with D’s metaprogramming capabilities lately, in particular code generation. Code generation in D is very simple, because one has to explicitly generate a string with the source code and then use the mixin operator to ask the compiler to insert it at the point of compilation. So for example writing mixin("Foo.bar;"); is exactly like writing Foo.bar; . This has the downside that it gives the programmer very little help in writing code the compiles, but is very flexible and avoid the need to use dark magic like it happens with annotations in Java, or template metaprogramming in C++.

D has also some introspection facilities, allowing the programmer to extract information about types and classes. These two things should give us the power to write code that “walks” an object and do some operations on it irrespective of the structure. An example would be a generic serialization library, or a documentation tool.

A (simple?) task

But is it easy to do ? I wanted to find out, so I set out with a simple example. Let’s take the following task: write a function that applies another function to every member variable of an object. In other words, we would like to be able to write the following code:

class Foo
{
public:
    int x;
    float y;
    void setX(int x) { this.x = x; }
};

void print_field(T)(T value)
{
    writefln("Value: %s", value);
}
/* ... */
void foo(Foo f)
{
    each_field!(Foo,"print_field")(f);
}

And obtain as result the values of the members x and y How can we write each_field ? Let’s start with the desired outcome. In the above class, the result should be equivalent to the following:

void foo(Foo f)
{
    print_field!int(f.x);
    print_field!float(f.y);
}

This means that we have to

  • Get the list of all the fields, with both the name and the type
  • Generate the above string
  • Call mixin to embed it in the desired place

Library and compiler support

Extraction of information about classes can be done in two ways: use the module std.traits or use the __traits keyword. Not sure about the rationale for putting some check in one place and others in the other, but in our case the closest to what we want is __traits(allMembers, Foo). This is not exactly what we would like, in fact this call has two issues.

The first is that allMembers returns all the members of the object, not only the instance variables; plus there aren’t other methods to directly check what we need: we have to exclude one by one what we don’t want.

The second, and more important, is that the information is returned as strings while the arguments are usually passed as types. This forces us to “transform back” the string to a type with another level of metaprogramming with static if or mixin or by passing the values as a template argument. In both cases the result is uglier than one would like. This is what I was able to write:

string[] get_members(T)()
{
    return [__traits(allMembers,T)]
        .filter!( a => a != "Monitor" )
        .filter!( a => a != "factory" )
        .array();
}

string each_field_worker(string klass, string var, string expr,string[] members)
{
    string result = "";
    foreach (string m; members)
    {
        string condition = format("!__traits(isVirtualFunction,%s.%s)
         && !__traits(isFinalFunction,%s.%s)
         && !__traits(isVirtualMethod,%s.%s) ", klass, m, klass, m, klass, m);
        result ~= format( "static if (%s) %s(%s.%s);\n", 
                          condition, expr, var, m );
    }
    return result;
}

void each_field(T,string expr)(T value)
{
    mixin(each_field_worker(__traits(identifier,T),"value", expr, get_members!T()));
}

The relevant line is result ~= format( "static if (%s) %s(%s.%s);\n", condition, expr, var, m );.

As we can see one has to resort to the use of static if for the checks to remove the methods. This adds quite a lot of noise to the code and probably is not efficient, since one may need to generate a lot of code which then will be discarded.

Conclusion

In the end what I set out to do was very doable, but I still don’t like the outcome.

What I would like to be able to write would be something like this:

string[] get_members(T)()
{
    return [__traits(allMembers,T)]
        .filter!( a => a != "Monitor" )
        .filter!( a => a != "factory" )
        .filter!( a => !__traits(isFinalFunction,T,a) )
        .filter!( a => !__traits(isVirtualFunction,T,a) )
        .filter!( a => !__traits(isVirtualMethod,T,a) )
        .array();
}

string each_field_worker(string var, string expr,string[] members)
{
    string result = "";
    foreach (string m; members)
    {
        result ~= format( "%s(%s.%s);\n", expr, var, m );
    }
    return result;
}

void each_field(T,string expr)(T value)
{
    mixin(each_field_worker("value", expr, get_members!T()));
}

This seems much more readable and also manageable. I have finally to add that I still don’t know well the language, so I’m probably missing some tricks, but in any case the language’s library could benefit from a partial redesign. In particular having to add the check inside the code to be compiled is a big drawback, requiring to pass around a lot of state.