Question

What is the coolest somewhat practical metaprogramming hack you've done or seen done in the D programming language? Somewhat practical means excluding, for example, the compile-time raytracer.

Was it helpful?

Solution

In terms of the outright coolest, I'd have to say Kirk McDonald's PyD (and other similar bindings) as these have do to a huge amount of work in detecting and handling lots of different types, as well as complex code generation.

That said, PyD only wins because BLADE technically uses CTFE, not templates.

On a more personal note, D templates have gotten extensive use in a research project of mine. It's a simulation framework where modules can define their own private data types. Exposing a new user type to the framework requires a single line of code which creates an XML parser for the type as well as associated network serialisation/deserialisation code.

OTHER TIPS

An arbitrary precision type It generates ASM code at compile time (before the compiler does)

DParse in Scrapple tools is a templated parser generator. However, ldc is the only D compiler with a functioning compile time GC (but even then it has a couple oddly random crashes). Ive played with it a little and you can do some interesting things like config file parsing and stuff, but until a compile time GC is fully running you cannot do big things.

The D/Objective-C Bridge uses templates to let you manipulate Cocoa objects in D.

My favorites would be ElemType and KeyType from tools.base:

template ElemType(T) {
  alias typeof((function() {
    foreach (elem; Init!(T)) return elem; assert(false);
  })()) ElemType;
}

template KeyType(T) {
  alias typeof((function() {
    foreach (key, elem; Init!(T)) return key; assert(false);
  })()) KeyType;
}

A united type template struct (It wont allow you to make unit errors.)

Compile time string hashing. You can use this to obfuscate embedded strings in your code. Just search for "hash". quite a few other interesting samples on that page, too.

One example is the bitfields facility in D's standard library which generates code for bit field manipulation starting from a user-specified layout.

The Tuple facility is another example. It generates a tuple based on user-provided types and optional names. There isn't a lot of generative umph in there save for injecting the named fields, but I think it's an illustrative example.

Without knowing of Lambert's exploit I just added memoize to the standard library - see here for the documentation, here for the code, and here for the related newsgroup discussion.

Another facility I worked on is a higher-order function that tabulates an integral or real-valued function (e.g. offers fast exponential). That's not ready for release yet.

Once object creation will be allowed during compilation, it will be easy to create e.g. regular expression engines that do all automata generation during compilation.

I'll answer my own question because this one didn't exist when I asked it. I wrote a patch to the garbage collector that uses templates and compile time introspection to generate the pointer offset information for arbitrarily complex user defined types to allow for precise heap scanning, instead of having this be done within the compiler.

I wrote a memoize() function whose header is this (the code is a bit long for pasting here):

auto memoize(TFunc)(TFunc func);

What it does is, you give it a function's address, and it returns a strongly-typed delegate (same signature and return type as the original function) that caches the return values of the original function, so that calling it twice with the same parameter only calls the underlying function once. For instance, here is a memoized, "recursive" definition of the Fibonacci sequence that executes in linear, rather than exponential, time:

uint fib(uint n) { return n > 0 ? n > 1 ? memoize(&fib)(n - 1) + memoize(&fib)(n - 2) : 1 : 0; }

You can call it normally, as in: fib(1000);


Edit: The previous code whose link I posted was rather hideous; this version is much more elegant.

Mixins to read and write simple structures from a Stream object:

template TStructReader() {
        private alias typeof(*this) T;
        static T opCall(Stream stream) {
                assert(stream.readable);
                T ret; stream.readExact(&ret, T.sizeof);
                return ret;
        }
}

template TStructWriter() {
        private alias typeof(*this) T;
        void write(Stream stream) {
                assert(stream.writeable);
                stream.writeExact(this, T.sizeof);
        }
}

Use it like this:

align (1) struct MyStruct {
        ... definitions here ...
        mixin TStructReader;
        mixin TStructWriter;
}

auto ms = MyStruct(stream);
ms.write(stream);

LuaD also extensively uses metaprogramming to seamlessly interact with Lua. You can register a whole class with a single command.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top