Jump to page: 1 25  
Page
Thread overview
Metaprogramming in D : Some Real-world Examples
Nov 10, 2009
Walter Bright
Nov 10, 2009
Bill Baxter
Nov 12, 2009
Bill Baxter
Nov 12, 2009
Bill Baxter
Nov 10, 2009
Nick Sabalausky
Nov 12, 2009
Bill Baxter
Nov 12, 2009
Nick Sabalausky
Nov 12, 2009
Nick Sabalausky
Nov 10, 2009
Denis Koroskin
Nov 12, 2009
Bill Baxter
Nov 10, 2009
Lutger
Nov 12, 2009
Bill Baxter
Nov 12, 2009
Lutger
Nov 10, 2009
Jacob Carlborg
Nov 10, 2009
Jacob Carlborg
Nov 10, 2009
Bill Baxter
Nov 10, 2009
grauzone
Nov 11, 2009
grauzone
Nov 11, 2009
Christopher Wright
Nov 11, 2009
Don
Nov 11, 2009
grauzone
Nov 11, 2009
grauzone
Nov 12, 2009
Jacob Carlborg
Nov 11, 2009
Max Samukha
Nov 12, 2009
Jeremie Pelletier
Nov 12, 2009
Bill Baxter
Nov 12, 2009
Denis Koroskin
Nov 13, 2009
rmcguire
Nov 12, 2009
Bill Baxter
Nov 13, 2009
Bill Baxter
Nov 19, 2009
Walter Bright
Nov 22, 2009
Long Chang
Nov 24, 2009
Lutger
Nov 24, 2009
Bill Baxter
Nov 25, 2009
Nick Sabalausky
Nov 25, 2009
Bill Baxter
Nov 25, 2009
BCS
Nov 25, 2009
Nick Sabalausky
Nov 25, 2009
BCS
November 10, 2009
Looks like Bill Baxter is giving a presentation on D Nov. 18!

http://www.nwcpp.org/
November 10, 2009
On Mon, Nov 9, 2009 at 4:09 PM, Walter Bright <newshound1@digitalmars.com> wrote:
> Looks like Bill Baxter is giving a presentation on D Nov. 18!
>
> http://www.nwcpp.org/

Yep, that's right, and I'd be quite grateful to you smart folks here if you could share your meta-programming favorites with me!   If you've got a real-world example of meta-programming in D that you think is particularly handy, then please send it my way

I'm looking for small-but-useful things that are easy to explain, and make something easier than it would be otherwise.  Things like places where static if can save your butt,  or loop unrolling,  and passing code snippets to functions like in std.algorithm.

Things like a compile-time raytracer or regexp parser (though quite cool!) are not what I'm after.  Too involved for a short talk.

--bb
November 10, 2009
Bill Baxter wrote:
> On Mon, Nov 9, 2009 at 4:09 PM, Walter Bright
> <newshound1@digitalmars.com> wrote:
>> Looks like Bill Baxter is giving a presentation on D Nov. 18!
>>
>> http://www.nwcpp.org/
> 
> Yep, that's right, and I'd be quite grateful to you smart folks here
> if you could share your meta-programming favorites with me!   If
> you've got a real-world example of meta-programming in D that you
> think is particularly handy, then please send it my way
> 
> I'm looking for small-but-useful things that are easy to explain, and
> make something easier than it would be otherwise.  Things like places
> where static if can save your butt,  or loop unrolling,  and passing
> code snippets to functions like in std.algorithm.
> 
> Things like a compile-time raytracer or regexp parser (though quite
> cool!) are not what I'm after.  Too involved for a short talk.
> 
> --bb

std.random has code that checks the parameters of a congruential RNG during compilation. That's also an example in TDPL.

Andrei
November 10, 2009
"Bill Baxter" <wbaxter@gmail.com> wrote in message news:mailman.290.1257812868.20261.digitalmars-d-announce@puremagic.com...
> On Mon, Nov 9, 2009 at 4:09 PM, Walter Bright <newshound1@digitalmars.com> wrote:
>> Looks like Bill Baxter is giving a presentation on D Nov. 18!
>>
>> http://www.nwcpp.org/
>
> Yep, that's right, and I'd be quite grateful to you smart folks here if you could share your meta-programming favorites with me!   If you've got a real-world example of meta-programming in D that you think is particularly handy, then please send it my way
>
> I'm looking for small-but-useful things that are easy to explain, and make something easier than it would be otherwise.  Things like places where static if can save your butt,  or loop unrolling,  and passing code snippets to functions like in std.algorithm.
>
> Things like a compile-time raytracer or regexp parser (though quite cool!) are not what I'm after.  Too involved for a short talk.
>
> --bb

I have a few things, mostly part of my SemiTwist D Tools project (http://www.dsource.org/projects/semitwist/):

=== Trace / Trace Value ===

Two of my personal favorites (particularly traceVal). Great for debugging.

Implementation and Documentation (search for "trace" and "traceVal", implementations are less than 10 lines each): http://www.dsource.org/projects/semitwist/browser/trunk/src/semitwist/util/mixins.d

Quick Example:
-----------------------------
mixin(trace!());
mixin(trace!("--EASY TO VISUALLY GREP--"));

int myVar=100;
mixin(traceVal!("myVar  "));
mixin(traceVal!("myVar-1"));
mixin(traceVal!("min(4,7)", "max(4,7)"));
-----------------------------

Output:
-----------------------------
C:\path\file.d(1): trace
--EASY TO VISUALLY GREP--: C:\path\file.d(3): trace
myVar  : 100
myVar-1: 99
min(4,7): 4
max(4,7): 7
-----------------------------

There's also a traceMixin that can be useful for debugging mixins (it'll replace a normal string mixin and echo at compile time via "pragma(msg, )" the string being mixed in).

=== Init Member ===

Great for DRY in constructors with many initialization parameters.

Implementation and Documentation (at the top of the file): http://www.dsource.org/projects/semitwist/browser/trunk/src/semitwist/util/mixins.d

Quick Example:
-----------------------------
mixin(initMember!(someVar));
mixin(initMember!(a, b, c));
-----------------------------

Turns Into:
-----------------------------
this.someVar = someVar;
this.a = a;
this.b = b;
this.c = c;
-----------------------------

Some variations are also available, such as initMemberFrom for copy constructors and initFrom copying class members to local vars.

=== Getters ===

DRY mixins for publicly read-only properties, and a "lazy" version for lazily computed & cached read-only properties. A poor replacement for a real DRY property syntax, but the next best thing.

Implementation and Documentation (search for "getter" and "getterLazy"): http://www.dsource.org/projects/semitwist/browser/trunk/src/semitwist/util/mixins.d

Quick Example:
-----------------------------
// Third param optional
mixin(getter!(float, "someFloat", 2.5));

mixin(getterLazy!(int, "myVar"));
private int _myVar_gen()
{
    // Ordinarily, this function would be much more complex
    // Also, any member func can set "_myVar_cached = false;"
    // to force this to be re-computed on the next request.
    return 7;
}
-----------------------------


Turns Into:
-----------------------------
private float _someFloat = 2.5;
private float someFloat(float _NEW_VAL_)
{
    _someFloat = _NEW_VAL_;
    return _someFloat;
}
public float someFloat()
{
    return _someFloat;
}

private int _myVar;
private bool _myVar_cached = false;
public int myVar() {
    if(!_myVar_cached) {
        _myVar_cached = true;
        _myVar = _myVar_gen();
    }
    return _myVar;
}
private int _myVar_gen()
{
    // Ordinarily, this function would be much more complex
    // Also, any member func can set "_myVar_cached = false;"
    // to force this to be re-computed on the next request.
    return 7;
}
-----------------------------

Variations are also available to use "protected" (or anything else) instead of private.

=== Defer Assert/Ensure ===

Uses metaprogramming to create an alternative to assert() that provides much of the usefulness of JUnit-style libs, but without the bulk of wrapping things like '==' and '||' in classes/structs or forcing unnatural syntax like '(a.equals(b)).or(c.notEquals(d))'. Also reports unexpected exceptions and allows requiring a particular exception to be thrown. Implemented in less than 200 lines, including blank lines and comments.

Implementation: http://www.dsource.org/projects/semitwist/browser/trunk/src/semitwist/util/deferAssert.d

Simple Test App: http://www.dsource.org/projects/semitwist/browser/trunk/src/semitwist/apps/tests/deferAssertTest/main.d

Quick Example:
-----------------------------
int foo = 2;
mixin(deferAssert!(`foo == 3 || foo > 5`, "foo is bad"));
mixin(deferEnsure!(`foo`, `_ == 3 || _ > 5`, "ensure foo failed"));
flushAsserts();
-----------------------------

Output:
-----------------------------
src\semitwist\apps\tests\deferAssertTest\main.d(37): Assert Failed (foo == 3
|| foo > 5): foo is bad
src\semitwist\apps\tests\deferAssertTest\main.d(42): Ensure Failed: ensure
foo failed
Expression 'foo':
Expected: _ == 3 || _ > 5
Actual: 2
tango.core.Exception.AssertException@src\semitwist\util\deferAssert.d(170):
2 Assert Failures
-----------------------------

=== Compile-time checking on types with non-identifier strings ===

Another of my favorites. This is from an upcoming release of my Goldie ( http://www.dsource.org/projects/goldie ) parser library.

I have a class to represent a token, which could have any name like "+" or "Statement", etc., all depending on the user-defined grammar. Currently, this token name representation is dynamic/run-time, which is very flexible, but there's no compile-time checking of these names, which often a bad tradeoff because many programs that need to parse something already know (in fact, *must* already know) the token names, so the flexibility doesn't help them at all, but compile-time checking would.

Unfortunately, the traditional approach to adding static checking would require every token name to be a valid identifier name, so for instance, "+" would have to be changed to "Plus", etc. And this can be problematic. It's extra work. It's very difficult to automate while getting good well-named results. It's possible (in a company setting, for instance) that the programmer might not be allowed or able to change the grammar. And of course, there's the possibility for name collisions (ie, what if "Plus" was already taken by another token?). Also, the new static class definition would probably need to be duplicated for each token. But all those problems can be solved in D quite easily with just a very small amount of some very simple metaprogramming.

The actual implementation Goldie uses does get fairly involved, but the basic concept is dead simple. All it takes is one templated type paramater, one static if and one static assert (and the static if could easily be eliminated):

-------------------------------------------------
// ----------- Dynamic Token -----------

// A Dynamic token. Flexible, but no compile-time checking
class DynamicToken
{
    protected char[] name;
    this(char[] name)
    {
        if(name != "+" && name != "Statement")
            throw new Exception("Invalid token: " ~ name);

        this.name = name;
    }
    // More Tokeny stuff here
}
unittest
{
    auto t1 = new DynamicToken("+");
    auto t2 = new DynamicToken("Statement");
    auto t3 = new DynamicToken("Stment"); // Runtime error
}

// ----------- Old-Style Static Token -----------

class OldStyle_StaticToken_Statement : DynamicToken
{
    this() { super("Statement"); }
}
// Note that "+" must be changed to "Plus",
// Also, the whole class definition has to be repeated
// (Although it's pretty small in this case.)
class OldStyle_StaticToken_Plus : DynamicToken
{
    this() { super("+"); }
}
unittest
{
    // Supposed to be +, but had to be changed to Plus
    // by either the grammar author or by special complex
    // logic in the StaticToken-generation tool.
    // And if there was already another token actually named "Plus"...
    // Well, even more complexity arises.

    auto t1 = new OldStyle_StaticToken_Plus;
    auto t2 = new OldStyle_StaticToken_Statement;
    //auto t3 = new OldStyle_StaticToken_Stment; // Compile-time error
}

// ----------- New-Style Static Token -----------

class NewStyle_StaticToken(char[] staticName) : DynamicToken
{
    static if(staticName != "+" && staticName != "Statement")
        static assert(false, "Invalid token: " ~ staticName);

    this() { super(staticName); }
}
unittest
{
    auto t1 = new NewStyle_StaticToken!("+");
    auto t2 = new NewStyle_StaticToken!("Statement");
    //auto t3 = new NewStyle_StaticToken!("Stment"); // Compile-time error
}
-------------------------------------------------


November 10, 2009
On Tue, 10 Nov 2009 03:27:20 +0300, Bill Baxter <wbaxter@gmail.com> wrote:

> On Mon, Nov 9, 2009 at 4:09 PM, Walter Bright
> <newshound1@digitalmars.com> wrote:
>> Looks like Bill Baxter is giving a presentation on D Nov. 18!
>>
>> http://www.nwcpp.org/
>
> Yep, that's right, and I'd be quite grateful to you smart folks here
> if you could share your meta-programming favorites with me!   If
> you've got a real-world example of meta-programming in D that you
> think is particularly handy, then please send it my way
>
> I'm looking for small-but-useful things that are easy to explain, and
> make something easier than it would be otherwise.  Things like places
> where static if can save your butt,  or loop unrolling,  and passing
> code snippets to functions like in std.algorithm.
>
> Things like a compile-time raytracer or regexp parser (though quite
> cool!) are not what I'm after.  Too involved for a short talk.
>
> --bb

kprintf (a printf variant) in XoMB is a nice example imo. It accepts format as a template parameter, doing all the checks at compile-time (and more).

http://github.com/xomboverlord/xomb-bare-bones/blob/6d924a9fd7cafe43aa50f38c0cd04c44187d4993/kernel/core/kprintf.d

/* This template will generate code for printing and will do
 * all parsing of the format string at compile time
 *
 * USAGE:
 *   kprintf!("format string {specifier} ... ")(args...);
 *
 * EXAMPLES:
 *   kprintf!("Integer: {}")(10);
 *   kprintf!("{!cls}Cleared the screen.")();
 *   kprintf!("{!pos:2,3}At position (2,3)")();
 *   kprintf!("{!fg:LightBlue!bg:Gray}{}")(25);
 *   kprintf!("{!fg:Red}redness")();
 *   kprintf!("{x} Hex!")(145);
 *   kprintf!("Curly Brace: {{")();
 *
 * COMMANDS:
 *   !cls - Clears the screen.
 *   !fg  - Sets the foreground color, see the Color enum
 *            in kernel/dev/console.d.
 *   !bg  - Sets the background color, same as above.
 *   !pos - Moves the cursor to the x and y given, see example above.
 *
 * SPECIFIERS:
 *   {x}  - Prints the hex value.
 *   {u}  - Treats as unsigned.
 *   {}   - Prints common form.
 *
 * WHY IS IT COOL?
 *   - Compile time parsing of format strings
 *   - Type checking at compile time as well
 *   - That means it can tell you that you are dumb before you execute.
 *   - No need to specify type information.
 *
 *   - So we can do this and not care about the
 *      output of the function:
 *
 *   auto blah = someFunction();
 *   kprintf!("Some Arbitrary Info: {}")(blah);
 *
 *      WOWWY WOW WOW!
 *
 */
November 10, 2009
Bill Baxter wrote:

> On Mon, Nov 9, 2009 at 4:09 PM, Walter Bright <newshound1@digitalmars.com> wrote:
>> Looks like Bill Baxter is giving a presentation on D Nov. 18!
>>
>> http://www.nwcpp.org/
> 
> Yep, that's right, and I'd be quite grateful to you smart folks here if you could share your meta-programming favorites with me!   If you've got a real-world example of meta-programming in D that you think is particularly handy, then please send it my way
> 
> I'm looking for small-but-useful things that are easy to explain, and make something easier than it would be otherwise.  Things like places where static if can save your butt,  or loop unrolling,  and passing code snippets to functions like in std.algorithm.
> 
> Things like a compile-time raytracer or regexp parser (though quite cool!) are not what I'm after.  Too involved for a short talk.
> 
> --bb

Great, I hope to see some slides or a video!

Here is a watered down example of what I currently use to help with the boilerplate code of a visitor. It doesn't look much, but it's helpful when you have lots of visitable classes and in case of adding new classes. The code should run as is:

import std.stdio;

enum Visitable =
q{
    override void accept(IVisitor visitor)
    {
        visitor.visit(this);
    }
};

interface IExpression
{
    void accept(IVisitor visitor);
}

class Sum : IExpression
{
    mixin(Visitable);
}

class Product : IExpression
{
    mixin(Visitable);
}

string visitMethodOf(string type)
{
    return "void visit(" ~ type ~ ");";
}

string FoldStringsOf(alias F)(string[] list)
{
    string result = "";
    foreach (element ; list)
        result ~= F(element);
    return result;
}

interface IVisitor
{
    mixin( FoldStringsOf!visitMethodOf( ["Sum", "Product"] ) );
}

class Visitor : IVisitor
{
    void visit(Sum node)
    {
        writeln("sum");
    }

    void visit(Product node)
    {
        writeln("product");
    }
}

void main()
{
    auto printer = new Visitor();

    IExpression sum = new Sum();
    IExpression product = new Product();

    sum.accept(printer);
    product.accept(printer);
}
November 10, 2009
On 11/10/09 01:27, Bill Baxter wrote:
> On Mon, Nov 9, 2009 at 4:09 PM, Walter Bright
> <newshound1@digitalmars.com>  wrote:
>> Looks like Bill Baxter is giving a presentation on D Nov. 18!
>>
>> http://www.nwcpp.org/
>
> Yep, that's right, and I'd be quite grateful to you smart folks here
> if you could share your meta-programming favorites with me!   If
> you've got a real-world example of meta-programming in D that you
> think is particularly handy, then please send it my way
>
> I'm looking for small-but-useful things that are easy to explain, and
> make something easier than it would be otherwise.  Things like places
> where static if can save your butt,  or loop unrolling,  and passing
> code snippets to functions like in std.algorithm.
>
> Things like a compile-time raytracer or regexp parser (though quite
> cool!) are not what I'm after.  Too involved for a short talk.
>
> --bb

This is invaluable to me, which makes it possible to do some form of duck typing at compile time:

static if (is(typeof({
/* does this compile */
})))

Then I have some other things, not the most useful stuff but still usable:

Get the name of a function
Get the parameter names of a function
Get the field names of a class/struct
Get/set private fields of a class/struct outside the module
Call a function with named arguments
Then some templates that check if a type has a (class) method

November 10, 2009
Jacob Carlborg wrote:
> On 11/10/09 01:27, Bill Baxter wrote:
>> On Mon, Nov 9, 2009 at 4:09 PM, Walter Bright
>> <newshound1@digitalmars.com>  wrote:
>>> Looks like Bill Baxter is giving a presentation on D Nov. 18!
>>>
>>> http://www.nwcpp.org/
>>
>> Yep, that's right, and I'd be quite grateful to you smart folks here
>> if you could share your meta-programming favorites with me!   If
>> you've got a real-world example of meta-programming in D that you
>> think is particularly handy, then please send it my way
>>
>> I'm looking for small-but-useful things that are easy to explain, and
>> make something easier than it would be otherwise.  Things like places
>> where static if can save your butt,  or loop unrolling,  and passing
>> code snippets to functions like in std.algorithm.
>>
>> Things like a compile-time raytracer or regexp parser (though quite
>> cool!) are not what I'm after.  Too involved for a short talk.
>>
>> --bb
> 
> This is invaluable to me, which makes it possible to do some form of duck typing at compile time:
> 
> static if (is(typeof({
> /* does this compile */
> })))

There are forces at work (Don, that is) attempting to get rid of that very construct and replace it with something better:

http://www.digitalmars.com/d/archives/digitalmars/D/Proposal_Replace_traits_and_is_typeof_XXX_with_a_magic_namespace_._99914.html

In my humble opinion, is(typeof({...})) is an ugly creature. I really don't think it should be put under a spotlight as a good example of D metaprogramming. If anything, please use __traits(compiles, {...}) instead.

-Lars
November 10, 2009
On 11/10/09 13:29, Lars T. Kyllingstad wrote:
> Jacob Carlborg wrote:
>> On 11/10/09 01:27, Bill Baxter wrote:
>>> On Mon, Nov 9, 2009 at 4:09 PM, Walter Bright
>>> <newshound1@digitalmars.com> wrote:
>>>> Looks like Bill Baxter is giving a presentation on D Nov. 18!
>>>>
>>>> http://www.nwcpp.org/
>>>
>>> Yep, that's right, and I'd be quite grateful to you smart folks here
>>> if you could share your meta-programming favorites with me! If
>>> you've got a real-world example of meta-programming in D that you
>>> think is particularly handy, then please send it my way
>>>
>>> I'm looking for small-but-useful things that are easy to explain, and
>>> make something easier than it would be otherwise. Things like places
>>> where static if can save your butt, or loop unrolling, and passing
>>> code snippets to functions like in std.algorithm.
>>>
>>> Things like a compile-time raytracer or regexp parser (though quite
>>> cool!) are not what I'm after. Too involved for a short talk.
>>>
>>> --bb
>>
>> This is invaluable to me, which makes it possible to do some form of
>> duck typing at compile time:
>>
>> static if (is(typeof({
>> /* does this compile */
>> })))
>
> There are forces at work (Don, that is) attempting to get rid of that
> very construct and replace it with something better:
>
> http://www.digitalmars.com/d/archives/digitalmars/D/Proposal_Replace_traits_and_is_typeof_XXX_with_a_magic_namespace_._99914.html
>
>
> In my humble opinion, is(typeof({...})) is an ugly creature. I really
> don't think it should be put under a spotlight as a good example of D
> metaprogramming. If anything, please use __traits(compiles, {...}) instead.
>
> -Lars

Yes, it's very ugly. As long as the functionality is left in the language I'm happy. I'm using D1 where __traits isn't available.
November 10, 2009
On Tue, Nov 10, 2009 at 4:29 AM, Lars T. Kyllingstad <public@kyllingen.nospamnet> wrote:
> Jacob Carlborg wrote:
>>
>> On 11/10/09 01:27, Bill Baxter wrote:
>>>
>>> On Mon, Nov 9, 2009 at 4:09 PM, Walter Bright <newshound1@digitalmars.com>  wrote:
>>>>
>>>> Looks like Bill Baxter is giving a presentation on D Nov. 18!
>>>>
>>>> http://www.nwcpp.org/
>>>
>>> Yep, that's right, and I'd be quite grateful to you smart folks here if you could share your meta-programming favorites with me!   If you've got a real-world example of meta-programming in D that you think is particularly handy, then please send it my way
>>>
>>> I'm looking for small-but-useful things that are easy to explain, and make something easier than it would be otherwise.  Things like places where static if can save your butt,  or loop unrolling,  and passing code snippets to functions like in std.algorithm.
>>>
>>> Things like a compile-time raytracer or regexp parser (though quite cool!) are not what I'm after.  Too involved for a short talk.
>>>
>>> --bb
>>
>> This is invaluable to me, which makes it possible to do some form of duck typing at compile time:
>>
>> static if (is(typeof({
>> /* does this compile */
>> })))
>
> There are forces at work (Don, that is) attempting to get rid of that very construct and replace it with something better:
>
> http://www.digitalmars.com/d/archives/digitalmars/D/Proposal_Replace_traits_and_is_typeof_XXX_with_a_magic_namespace_._99914.html
>
> In my humble opinion, is(typeof({...})) is an ugly creature. I really don't
> think it should be put under a spotlight as a good example of D
> metaprogramming. If anything, please use __traits(compiles, {...}) instead.

I really liked the meta.compiles(...) or meta(compiles, ...) idea.

You're right though.  I would rather show things that look deliberately designed to do the job nicely instead of things that look like hacks.   Unfortunately, a lot of "real-world" D meta-programming currently requires hacky-looking things.  So I can't really avoid them all.

--bb
« First   ‹ Prev
1 2 3 4 5