www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Metaprogramming work around

reply =?UTF-8?B?IkVyw6hiZSI=?= <erebe erebe.eu> writes:
Hi,

I'm working on some metaprogramming code which implement a 
Factory and generate an enum from a list of string.

So here my questions :

1) The documentation say mixin templates could take as 
TemplateParameterList
a "TemplateParameter , TemplateParameterList" but all my tried to 
instaciate this template failed lamentably.

mixin template Foo(T, R...)
{

    anotherTemplate!(T);
    Foo!(R);

}

mixin Foo!( string, string, string);

Is something wrong with variadic template and mixin, do i miss 
something ?


2) Below some code I writed and I wanted to know if you have some 
advice to improve it (Right maner to do it, TypeChecking, Safety, 
...) <- variaidc arguments


The code is working is purpose is to create an enum of commands 
and to create a factory which returns me the command associated 
to a string.

Thanks !

===========================Code============================================
import std.stdio;
import std.traits;
import std.conv;


//Use to create the enums of every commands
mixin template enumGenerator( T... )
{

     template generate( T... )
     {
         enum string value = T[0] ~ ", " ~ generate!( T[2..$] 
).value;
     }

     template generate() { enum string value = "UNKNOW"; }


     //Here the creation of the enum
     mixin("enum Command { " ~ generate!(T).value ~ "};");

}

//Generate a function which return a command in regard of a string
mixin template factoryGenerator( T... )
{
     template generate( T... )
     {
         enum string value = "if( cmd == \"" ~ T[1] ~ "\")"
                                 ~ "return Command." ~ T[0] ~ ";"
                             ~ "else "
                                 ~ generate!(T[2..$]).value;
     }

     template generate() { enum string value = "return 
Command.UNKNOW;"; }

     //The function in question
     auto CommandFactory( string cmd )
     {
             mixin( generate!(T).value );
     }

}


mixin template IrcCommands( T... )
{

    mixin enumGenerator!( T );
    mixin factoryGenerator!( T );

}


void main()
{

                        /*Command*/     /*String associated*/
    mixin IrcCommands!( "Connected",    "001",
                        "NicknameUsed", "433",
                        "Message",      "PRIVMSG",
                        "UserLeaved",   "PART",
                        "UserJoined",   "JOIN",
                        "UserQuit",     "QUIT"
                        "Ping",         "PING" );

    writefln( to!string(CommandFactory("001")) );


}
Apr 17 2012
next sibling parent reply "Kenji Hara" <k.hara.pg gmail.com> writes:
On Tuesday, 17 April 2012 at 08:28:45 UTC, Erèbe wrote:
 Hi,

 I'm working on some metaprogramming code which implement a 
 Factory and generate an enum from a list of string.

 So here my questions :

 1) The documentation say mixin templates could take as 
 TemplateParameterList
 a "TemplateParameter , TemplateParameterList" but all my tried 
 to instaciate this template failed lamentably.

 mixin template Foo(T, R...)
 {

    anotherTemplate!(T);
    Foo!(R);

 }

 mixin Foo!( string, string, string);

 Is something wrong with variadic template and mixin, do i miss 
 something ?


 2) Below some code I writed and I wanted to know if you have 
 some advice to improve it (Right maner to do it, TypeChecking, 
 Safety, ...) <- variaidc arguments


 The code is working is purpose is to create an enum of commands 
 and to create a factory which returns me the command associated 
 to a string.

 Thanks !

 ===========================Code============================================
 import std.stdio;
 import std.traits;
 import std.conv;


 //Use to create the enums of every commands
 mixin template enumGenerator( T... )
 {

     template generate( T... )
     {
         enum string value = T[0] ~ ", " ~ generate!( T[2..$] 
 ).value;
     }

     template generate() { enum string value = "UNKNOW"; }


     //Here the creation of the enum
     mixin("enum Command { " ~ generate!(T).value ~ "};");

 }

 //Generate a function which return a command in regard of a 
 string
 mixin template factoryGenerator( T... )
 {
     template generate( T... )
     {
         enum string value = "if( cmd == \"" ~ T[1] ~ "\")"
                                 ~ "return Command." ~ T[0] ~ ";"
                             ~ "else "
                                 ~ generate!(T[2..$]).value;
     }

     template generate() { enum string value = "return 
 Command.UNKNOW;"; }

     //The function in question
     auto CommandFactory( string cmd )
     {
             mixin( generate!(T).value );
     }

 }


 mixin template IrcCommands( T... )
 {

    mixin enumGenerator!( T );
    mixin factoryGenerator!( T );

 }


 void main()
 {

                        /*Command*/     /*String associated*/
    mixin IrcCommands!( "Connected",    "001",
                        "NicknameUsed", "433",
                        "Message",      "PRIVMSG",
                        "UserLeaved",   "PART",
                        "UserJoined",   "JOIN",
                        "UserQuit",     "QUIT"
"UserQuit", "QUIT", // lack of comma
                        "Ping",         "PING" );

    writefln( to!string(CommandFactory("001")) );


 }
You can debug templates with adding static assertions in some where, like: mixin template enumGenerator( T... ) { template generate( T... ) { static assert(T.length%2==0 && is(typeof(T[0]) : string)); // check enum string value = T[0] ~ ", " ~ generate!( T[2..$] ).value; } //[snip] } mixin template factoryGenerator( T... ) { template generate( T... ) { static assert(T.length%2==0 && is(typeof(T[1]) : string)); // check enum string value = "if( cmd == \"" ~ T[1] ~ "\")" ~ "return Command." ~ T[0] ~ ";" ~ "else " ~ generate!(T[2..$]).value; } //[snip] } Bye. Kenji Hara
Apr 17 2012
parent reply =?UTF-8?B?IkVyw6hiZSI=?= <erebe erebe.eu> writes:
On Tuesday, 17 April 2012 at 10:29:56 UTC, Kenji Hara wrote:
 On Tuesday, 17 April 2012 at 08:28:45 UTC, Erèbe wrote:
 Hi,

 I'm working on some metaprogramming code which implement a 
 Factory and generate an enum from a list of string.

 So here my questions :

 1) The documentation say mixin templates could take as 
 TemplateParameterList
 a "TemplateParameter , TemplateParameterList" but all my tried 
 to instaciate this template failed lamentably.

 mixin template Foo(T, R...)
 {

   anotherTemplate!(T);
   Foo!(R);

 }

 mixin Foo!( string, string, string);

 Is something wrong with variadic template and mixin, do i miss 
 something ?


 2) Below some code I writed and I wanted to know if you have 
 some advice to improve it (Right maner to do it, TypeChecking, 
 Safety, ...) <- variaidc arguments


 The code is working is purpose is to create an enum of 
 commands and to create a factory which returns me the command 
 associated to a string.

 Thanks !

 ===========================Code============================================
 import std.stdio;
 import std.traits;
 import std.conv;


 //Use to create the enums of every commands
 mixin template enumGenerator( T... )
 {

    template generate( T... )
    {
        enum string value = T[0] ~ ", " ~ generate!( T[2..$] 
 ).value;
    }

    template generate() { enum string value = "UNKNOW"; }


    //Here the creation of the enum
    mixin("enum Command { " ~ generate!(T).value ~ "};");

 }

 //Generate a function which return a command in regard of a 
 string
 mixin template factoryGenerator( T... )
 {
    template generate( T... )
    {
        enum string value = "if( cmd == \"" ~ T[1] ~ "\")"
                                ~ "return Command." ~ T[0] ~ ";"
                            ~ "else "
                                ~ generate!(T[2..$]).value;
    }

    template generate() { enum string value = "return 
 Command.UNKNOW;"; }

    //The function in question
    auto CommandFactory( string cmd )
    {
            mixin( generate!(T).value );
    }

 }


 mixin template IrcCommands( T... )
 {

   mixin enumGenerator!( T );
   mixin factoryGenerator!( T );

 }


 void main()
 {

                       /*Command*/     /*String associated*/
   mixin IrcCommands!( "Connected",    "001",
                       "NicknameUsed", "433",
                       "Message",      "PRIVMSG",
                       "UserLeaved",   "PART",
                       "UserJoined",   "JOIN",
                       "UserQuit",     "QUIT"
"UserQuit", "QUIT", // lack of comma
                       "Ping",         "PING" );

   writefln( to!string(CommandFactory("001")) );


 }
You can debug templates with adding static assertions in some where, like: mixin template enumGenerator( T... ) { template generate( T... ) { static assert(T.length%2==0 && is(typeof(T[0]) : string)); // check enum string value = T[0] ~ ", " ~ generate!( T[2..$] ).value; } //[snip] } mixin template factoryGenerator( T... ) { template generate( T... ) { static assert(T.length%2==0 && is(typeof(T[1]) : string)); // check enum string value = "if( cmd == \"" ~ T[1] ~ "\")" ~ "return Command." ~ T[0] ~ ";" ~ "else " ~ generate!(T[2..$]).value; } //[snip] } Bye. Kenji Hara
Thanks for the comma ! The issue with static assert (in my case) is that the compiler blow you a full page of "template's instatiation error" before the message of your assert. Ok not even a page of the size of c++ template error, but that lead to your message be less noticeable. While browsering the standard librairy I found this : static if ( expression ) //put your code here else assert(false, "your message"); With this, the compiler print just one line, "your message". That pretty neat and readable enough for me :)
 Stick in the magic pragma(msg, value); in here you won't regret 
 it ;)
 Another important thing to note here is that you should really 
 reconsider using plain if/else if it's a production code not 
 some toy to learn meta programming.
 At very least try to generate switch over strings but I don't 
 think any D compiler optimizes it. (but it should in future)
 Real world options are binary search on string table or even 
 better built-in hash table.
Thanks for pragma, it's awesome ! You guessed right, this code is just for the sake of learning some D meta programming. But I will try with an built-in hash table. There is something I still don't understand : mixin template Foo( T... ) { //Code here } mixin Foo!( "Hello", "Word" ); <---- Good -------------------------------------------- mixin template Foo( A, T... ) { //code here } mixin Foo!( "Hello", "Word" ); <--- Fail ! mixin Foo!( string, "Word" ); <---- Good -------------------------------------------- mixin template Foo( alias A, T... ) { //code here } mixin Foo!( "Hello", "world" ); <--- Good mixin Foo!( string, "world" ); <--- Fail ! --------------------------------------------- Is there someone to enlight me about this behavior ?
Apr 17 2012
parent reply "Kenji Hara" <k.hara.pg gmail.com> writes:
On Tuesday, 17 April 2012 at 12:04:44 UTC, Erèbe wrote:
[snip]
 There is something I still don't understand :

 mixin template Foo( T... )
 {
 //Code here
 }

 mixin Foo!( "Hello", "Word" ); <---- Good
T is TemplateTypeParameter, and matches any kind of template arguments - types, values, and symbols. The both arguments "Hello" and "World" are values, so you can bind them with T. http://dlang.org/template.html#TemplateTupleParameter
 --------------------------------------------

 "mixin template Foo( A, T... )
 {
 //code here
 }

 mixin Foo!( "Hello", "Word" ); <--- Fail !
 mixin Foo!( string, "Word" ); <---- Good
 --------------------------------------------
'A' is TemplateTypeParameter, and it matches only types. In the first instantiation of Foo, A doesn't match with the value "hello". In the second instantiation, string is type, and T matches with it. http://dlang.org/template.html#TemplateTypeParameter
 mixin template Foo( alias A, T... )
 {
 //code here
 }

 mixin Foo!( "Hello", "world" ); <--- Good
 mixin Foo!( string, "world" ); <--- Fail !

 ---------------------------------------------
'alias A' is TemplateAliasParameter, and it matches both symbols and values. Then A matches with the value "Hello", but doesn't with the type string. (string is an aliased name of immutable(char)[], and it is built-in array type.) http://dlang.org/template.html#TemplateAliasParameter Kenji Hara
Apr 17 2012
parent =?UTF-8?B?IkVyw6hiZSI=?= <erebe erebe.eu> writes:
On Tuesday, 17 April 2012 at 12:46:28 UTC, Kenji Hara wrote:
 On Tuesday, 17 April 2012 at 12:04:44 UTC, Erèbe wrote:
 [snip]
 There is something I still don't understand :

 mixin template Foo( T... )
 {
 //Code here
 }

 mixin Foo!( "Hello", "Word" ); <---- Good
T is TemplateTypeParameter, and matches any kind of template arguments - types, values, and symbols. The both arguments "Hello" and "World" are values, so you can bind them with T. http://dlang.org/template.html#TemplateTupleParameter
 --------------------------------------------

 "mixin template Foo( A, T... )
 {
 //code here
 }

 mixin Foo!( "Hello", "Word" ); <--- Fail !
 mixin Foo!( string, "Word" ); <---- Good
 --------------------------------------------
'A' is TemplateTypeParameter, and it matches only types. In the first instantiation of Foo, A doesn't match with the value "hello". In the second instantiation, string is type, and T matches with it. http://dlang.org/template.html#TemplateTypeParameter
 mixin template Foo( alias A, T... )
 {
 //code here
 }

 mixin Foo!( "Hello", "world" ); <--- Good
 mixin Foo!( string, "world" ); <--- Fail !

 ---------------------------------------------
'alias A' is TemplateAliasParameter, and it matches both symbols and values. Then A matches with the value "Hello", but doesn't with the type string. (string is an aliased name of immutable(char)[], and it is built-in array type.) http://dlang.org/template.html#TemplateAliasParameter Kenji Hara
Thanks a lot Kenji Hara, I have a better understanding of it now !
Apr 17 2012
prev sibling parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 17.04.2012 12:28, "Erèbe" wrote:
 Hi,

 I'm working on some metaprogramming code which implement a Factory and
 generate an enum from a list of string.

 So here my questions :

 1) The documentation say mixin templates could take as
 TemplateParameterList
 a "TemplateParameter , TemplateParameterList" but all my tried to
 instaciate this template failed lamentably.

 mixin template Foo(T, R...)
 {

 anotherTemplate!(T);
 Foo!(R);

 }

 mixin Foo!( string, string, string);

 Is something wrong with variadic template and mixin, do i miss something ?


 2) Below some code I writed and I wanted to know if you have some advice
 to improve it (Right maner to do it, TypeChecking, Safety, ...) <-
 variaidc arguments


 The code is working is purpose is to create an enum of commands and to
 create a factory which returns me the command associated to a string.

 Thanks !

 ===========================Code============================================
 import std.stdio;
 import std.traits;
 import std.conv;


 //Use to create the enums of every commands
 mixin template enumGenerator( T... )
 {

 template generate( T... )
 {
 enum string value = T[0] ~ ", " ~ generate!( T[2..$] ).value;
 }

 template generate() { enum string value = "UNKNOW"; }


 //Here the creation of the enum
 mixin("enum Command { " ~ generate!(T).value ~ "};");

 }

 //Generate a function which return a command in regard of a string
 mixin template factoryGenerator( T... )
 {
 template generate( T... )
 {
 enum string value = "if( cmd == \"" ~ T[1] ~ "\")"
 ~ "return Command." ~ T[0] ~ ";"
 ~ "else "
 ~ generate!(T[2..$]).value;
Stick in the magic pragma(msg, value); in here you won't regret it ;)
 }
Another important thing to note here is that you should really reconsider using plain if/else if it's a production code not some toy to learn meta programming. At very least try to generate switch over strings but I don't think any D compiler optimizes it. (but it should in future) Real world options are binary search on string table or even better built-in hash table. -- Dmitry Olshansky
Apr 17 2012