www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - [Article Submission] Have Your Efficiency, and Flexibility Too

reply "Nick Sabalausky" <a a.a> writes:
Getting in just under the wire here. I seem to have misjudged the scope of 
my topic, it ended up a bit large... Anyway, here's my entry:

http://www.semitwist.com/articles/EfficientAndFlexible/SinglePage/
May 30 2011
next sibling parent reply "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
On Tue, 31 May 2011 02:36:58 -0400, Nick Sabalausky wrote:

 Getting in just under the wire here. I seem to have misjudged the scope
 of my topic, it ended up a bit large... Anyway, here's my entry:
 
 http://www.semitwist.com/articles/EfficientAndFlexible/SinglePage/
Nice article. :) Some of the code snippets were a bit on the longish side, but I can't really say how they could be reduced. The narrative is a nice touch. May I make two small suggestions regarding the ex5_meta_deadDuck1.d snippet? Firstly, I cringe whenever I see is(typeof((){...})) being used to test whether something compiles or not. I'd much prefer immutable bool isIGizmo = __traits(compiles, { ... }); Granted, __traits() is pretty ugly too, but at least you have the "compiles" directive making it clear what's going on. Secondly, you could replace the immutable(void[0]) member with an enum, which also doesn't take up any space. I find enum _this_implements_interface_IGizmo_ = true; a lot more descriptive of its purpose. Then you could also replace the "auto dummy = T._this_implements..." line with static assert (T._this_implements_interface_IGizmo_); which will fail if _this_implements... isn't declared or if it's declared to be false. -Lars
May 31 2011
parent "Nick Sabalausky" <a a.a> writes:
"Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> wrote in message 
news:is2aah$29pf$1 digitalmars.com...
 On Tue, 31 May 2011 02:36:58 -0400, Nick Sabalausky wrote:

 Getting in just under the wire here. I seem to have misjudged the scope
 of my topic, it ended up a bit large... Anyway, here's my entry:

 http://www.semitwist.com/articles/EfficientAndFlexible/SinglePage/
Nice article. :) Some of the code snippets were a bit on the longish side, but I can't really say how they could be reduced. The narrative is a nice touch.
Thanks :)
 May I make two small suggestions regarding the ex5_meta_deadDuck1.d
 snippet?  Firstly, I cringe whenever I see is(typeof((){...})) being used
 to test whether something compiles or not.  I'd much prefer

    immutable bool isIGizmo = __traits(compiles,
    {
        ...
    });

 Granted, __traits() is pretty ugly too, but at least you have the
 "compiles" directive making it clear what's going on.

 Secondly, you could replace the immutable(void[0]) member with an enum,
 which also doesn't take up any space.  I find

    enum _this_implements_interface_IGizmo_ = true;

 a lot more descriptive of its purpose.  Then you could also replace the
 "auto dummy = T._this_implements..." line with

    static assert (T._this_implements_interface_IGizmo_);

 which will fail if _this_implements... isn't declared or if it's declared
 to be false.
All good points.
May 31 2011
prev sibling next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Nick Sabalausky:

 http://www.semitwist.com/articles/EfficientAndFlexible/SinglePage/
Regarding your addGizmos() in ex6_meta_flex3_runtimeToCompileTime1.d: void addGizmos(int numPorts, bool isSpinnable, int numGizmos) { // Dispatch to correct version of addGizmosTo. // Effectively converts a runtime value to compile-time. if (numPorts == 1) { if (isSpinnable) addGizmosTo!(1, true )(numGizmos); else addGizmosTo!(1, false)(numGizmos); } else if (numPorts == 2) { if (isSpinnable) addGizmosTo!(2, true )(numGizmos); else addGizmosTo!(2, false)(numGizmos); } else if (numPorts == 3) { if (isSpinnable) addGizmosTo!(3, true )(numGizmos); else addGizmosTo!(3, false)(numGizmos); } else if (numPorts == 5) { if (isSpinnable) addGizmosTo!(5, true )(numGizmos); else addGizmosTo!(5, false)(numGizmos); } else if (numPorts == 10) { if (isSpinnable) addGizmosTo!(10, true )(numGizmos); else addGizmosTo!(10, false)(numGizmos); } else throw new Exception(to!string(numPorts)~"-port Gizmo not supported."); } A shorter way to write it: void addGizmos(int numPorts, bool isSpinnable, int numGizmos) { foreach (np; TypeTuple!(1, 2, 3, 5, 10)) if (numPorts == np) { foreach (b; TypeTuple!(true, false)) if (isSpinnable == b) addGizmosTo!(np, b)(numGizmos); return; } throw new Exception(text(numPorts) ~ "-port Gizmo not supported."); } Bye, bearophile
May 31 2011
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
bearophile wrote:
 ...
 A shorter way to write it:

 void addGizmos(int numPorts, bool isSpinnable, int numGizmos) {
     foreach (np; TypeTuple!(1, 2, 3, 5, 10))
         if (numPorts == np) {
             foreach (b; TypeTuple!(true, false))
                 if (isSpinnable == b)
                     addGizmosTo!(np, b)(numGizmos);
             return;
         }

     throw new Exception(text(numPorts) ~ "-port Gizmo not supported.");
 }

 Bye,
 bearophile
Nice, but isSpinnable is always checked twice with your approach. Better: void addGizmos(int numPorts, bool isSpinnable, int numGizmos) { foreach (np; TypeTuple!(1, 2, 3, 5, 10)) if (numPorts == np) { if (isSpinnable) addGizmosTo!(np, true)(numGizmos); else addGizmosTo!(np, false)(numGizmos); return; } throw new Exception(text(numPorts) ~ "-port Gizmo not supported."); } Article: A very good read, it does not get boring even though it is quite long. I like it. Small nitpick: mixin(declareInterface("IGizmo", "Gizmo!(numPorts, isSpinnable)")); It seems like this should be a mixin template, not a string mixin. Also you wouldn't normally want to specify ThisType. Use typeof(this): mixin template declareInterface(string interfaceName){ mixin(`enum _this_implements_interface_`~interfaceName~`=true;`); mixin(`static assert( is`~interfaceName~`!(typeof(this)), "This type fails to implement `~interfaceName~`" );` ); } and then you do just: mixin declareInterface!"IGizmo"; Timon
May 31 2011
next sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Timon Gehr" <timon.gehr gmx.ch> wrote in message 
news:is2lts$2fcn$1 digitalmars.com...
  Article: A very good read, it does not get boring even though it is quite 
 long. I
 like it.
Thanks :)
 Small nitpick:
 mixin(declareInterface("IGizmo", "Gizmo!(numPorts, isSpinnable)"));

 It seems like this should be a mixin template, not a string mixin. Also 
 you
 wouldn't normally want to specify ThisType. Use typeof(this):

 mixin template declareInterface(string interfaceName){
    mixin(`enum _this_implements_interface_`~interfaceName~`=true;`);
    mixin(`static assert(
               is`~interfaceName~`!(typeof(this)),

               "This type fails to implement `~interfaceName~`"
           );`
    );
 }

 and then you do just:
 mixin declareInterface!"IGizmo";
I like the idea, but I just tried it and when I do that, 'isIGizmo' doesn't seem to be able to find the '_this_implements_interface_IGizmo' (using DMD 2.053). But, I wonder if that approach might be getting a little too fancy for this anyway. That would definitely be the right way to go for a real library, but for the article, the simpler it is to understand how it works, the better, and putting string mixins inside a template mixin is more to understand than just a string mixin (of course, I'm using CTFE too, but that's probably conceptually simpler for most people than template mixins).
May 31 2011
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
Nick Sabalausky wrote:
 "Timon Gehr" <timon.gehr gmx.ch> wrote in message
 news:is2lts$2fcn$1 digitalmars.com...
  Article: A very good read, it does not get boring even though it is quite
 long. I
 like it.
Thanks :)
 Small nitpick:
 mixin(declareInterface("IGizmo", "Gizmo!(numPorts, isSpinnable)"));

 It seems like this should be a mixin template, not a string mixin. Also
 you
 wouldn't normally want to specify ThisType. Use typeof(this):

 mixin template declareInterface(string interfaceName){
    mixin(`enum _this_implements_interface_`~interfaceName~`=true;`);
    mixin(`static assert(
               is`~interfaceName~`!(typeof(this)),

               "This type fails to implement `~interfaceName~`"
           );`
    );
 }

 and then you do just:
 mixin declareInterface!"IGizmo";
I like the idea, but I just tried it and when I do that, 'isIGizmo' doesn't seem to be able to find the '_this_implements_interface_IGizmo' (using DMD 2.053). But, I wonder if that approach might be getting a little too fancy for this anyway. That would definitely be the right way to go for a real library, but for the article, the simpler it is to understand how it works, the better, and putting string mixins inside a template mixin is more to understand than just a string mixin (of course, I'm using CTFE too, but that's probably conceptually simpler for most people than template mixins).
Okay. Valid point. It is true that making the article more complicated is not really an option. But you might want to add a comment that for serious work, template mixins would be better suited (otherwise people will almost certainly copy the string mixin approach ;)) It works for me. Are you sure you did not accidentally break some other part of your __traits(compiles,...) ? My minimal test case: template isIGizmo(T){enum isIGizmo=__traits(compiles,{static assert(T._this_implements_interface_IGizmo);});} mixin template declareInterface(string interfaceName){ mixin(`enum _this_implements_interface_`~interfaceName~`=true;`); mixin(`static assert( is`~interfaceName~`!(typeof(this)), "This type fails to implement `~interfaceName~`" );` ); } struct Gizmo{mixin declareInterface!"IGizmo";} static assert(isIGizmo!Gizmo); void main(){} Timon
May 31 2011
parent reply "Nick Sabalausky" <a a.a> writes:
"Timon Gehr" <timon.gehr gmx.ch> wrote in message 
news:is3rb5$1g32$1 digitalmars.com...
 Nick Sabalausky wrote:
 "Timon Gehr" <timon.gehr gmx.ch> wrote in message
 news:is2lts$2fcn$1 digitalmars.com...
  Article: A very good read, it does not get boring even though it is 
 quite
 long. I
 like it.
Thanks :)
 Small nitpick:
 mixin(declareInterface("IGizmo", "Gizmo!(numPorts, isSpinnable)"));

 It seems like this should be a mixin template, not a string mixin. Also
 you
 wouldn't normally want to specify ThisType. Use typeof(this):

 mixin template declareInterface(string interfaceName){
    mixin(`enum _this_implements_interface_`~interfaceName~`=true;`);
    mixin(`static assert(
               is`~interfaceName~`!(typeof(this)),

               "This type fails to implement `~interfaceName~`"
           );`
    );
 }

 and then you do just:
 mixin declareInterface!"IGizmo";
I like the idea, but I just tried it and when I do that, 'isIGizmo' doesn't seem to be able to find the '_this_implements_interface_IGizmo' (using DMD 2.053). But, I wonder if that approach might be getting a little too fancy for this anyway. That would definitely be the right way to go for a real library, but for the article, the simpler it is to understand how it works, the better, and putting string mixins inside a template mixin is more to understand than just a string mixin (of course, I'm using CTFE too, but that's probably conceptually simpler for most people than template mixins).
Okay. Valid point. It is true that making the article more complicated is not really an option. But you might want to add a comment that for serious work, template mixins would be better suited (otherwise people will almost certainly copy the string mixin approach ;)) It works for me. Are you sure you did not accidentally break some other part of your __traits(compiles,...) ? My minimal test case: template isIGizmo(T){enum isIGizmo=__traits(compiles,{static assert(T._this_implements_interface_IGizmo);});} mixin template declareInterface(string interfaceName){ mixin(`enum _this_implements_interface_`~interfaceName~`=true;`); mixin(`static assert( is`~interfaceName~`!(typeof(this)), "This type fails to implement `~interfaceName~`" );` ); } struct Gizmo{mixin declareInterface!"IGizmo";} static assert(isIGizmo!Gizmo); void main(){}
Hmm, something screwey seems to be going on. Your test example works for me too, but I could swear I've checked and double-checked everything (including the "__traits(compiles,...)") , and made your test case and my example as close to each other as I can, and I still can't seem to narrow down what's different. I do know this: In my code, I can't use typeof(this) because the compiler complains that "this" is only valid inside a member function. I have no idea why doing that seems to work, even for me, in your test case.
May 31 2011
parent reply "Nick Sabalausky" <a a.a> writes:
"Nick Sabalausky" <a a.a> wrote in message 
news:is3tk5$1j2n$1 digitalmars.com...
 "Timon Gehr" <timon.gehr gmx.ch> wrote in message 
 news:is3rb5$1g32$1 digitalmars.com...
 It works for me. Are you sure you did not accidentally break some other 
 part of
 your __traits(compiles,...) ?

 My minimal test case:

 template isIGizmo(T){enum isIGizmo=__traits(compiles,{static
 assert(T._this_implements_interface_IGizmo);});}

 mixin template declareInterface(string interfaceName){
    mixin(`enum _this_implements_interface_`~interfaceName~`=true;`);
    mixin(`static assert(

               is`~interfaceName~`!(typeof(this)),

               "This type fails to implement `~interfaceName~`"

           );`
    );
 }

 struct Gizmo{mixin declareInterface!"IGizmo";}

 static assert(isIGizmo!Gizmo);

 void main(){}
Hmm, something screwey seems to be going on. Your test example works for me too, but I could swear I've checked and double-checked everything (including the "__traits(compiles,...)") , and made your test case and my example as close to each other as I can, and I still can't seem to narrow down what's different. I do know this: In my code, I can't use typeof(this) because the compiler complains that "this" is only valid inside a member function. I have no idea why doing that seems to work, even for me, in your test case.
I think typeof(this) just seems to be screwy. Check this out: struct Gizmo { static assert( is(typeof(this)==Gizmo) ); } void main() {} Error: static assert (is(typeof(__error) == Gizmo)) is false But this is fine: struct Gizmo { alias typeof(this) Foo; typeof(this)* ptr; }
May 31 2011
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 31 May 2011 19:32:59 -0400, Nick Sabalausky <a a.a> wrote:

 "Nick Sabalausky" <a a.a> wrote in message
 news:is3tk5$1j2n$1 digitalmars.com...
 "Timon Gehr" <timon.gehr gmx.ch> wrote in message
 news:is3rb5$1g32$1 digitalmars.com...
 It works for me. Are you sure you did not accidentally break some other
 part of
 your __traits(compiles,...) ?

 My minimal test case:

 template isIGizmo(T){enum isIGizmo=__traits(compiles,{static
 assert(T._this_implements_interface_IGizmo);});}

 mixin template declareInterface(string interfaceName){
    mixin(`enum _this_implements_interface_`~interfaceName~`=true;`);
    mixin(`static assert(

               is`~interfaceName~`!(typeof(this)),

               "This type fails to implement `~interfaceName~`"

           );`
    );
 }

 struct Gizmo{mixin declareInterface!"IGizmo";}

 static assert(isIGizmo!Gizmo);

 void main(){}
Hmm, something screwey seems to be going on. Your test example works for me too, but I could swear I've checked and double-checked everything (including the "__traits(compiles,...)") , and made your test case and my example as close to each other as I can, and I still can't seem to narrow down what's different. I do know this: In my code, I can't use typeof(this) because the compiler complains that "this" is only valid inside a member function. I have no idea why doing that seems to work, even for me, in your test case.
I think typeof(this) just seems to be screwy. Check this out: struct Gizmo { static assert( is(typeof(this)==Gizmo) ); } void main() {} Error: static assert (is(typeof(__error) == Gizmo)) is false But this is fine: struct Gizmo { alias typeof(this) Foo; typeof(this)* ptr; }
I think there are certain special situations where you can use typeof(this). For example, as the return type for a static method. *looks for doc* Couldn't find any documentation on it... It's somewhat like static this, which is inflexible in how you write it. -Steve
Jun 01 2011
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
Steven Schveighoffer wrote:
 I think there are certain special situations where you can use
 typeof(this).  For example, as the return type for a static method.

 *looks for doc*  Couldn't find any documentation on it...

 It's somewhat like static this, which is inflexible in how you write it.

 -Steve
It is not documented in detail but it is there =). See: http://www.digitalmars.com/d/2.0/declaration.html "1. typeof(this) will generate the type of what this would be in a non-static member function, even if not in a member function. " Therefore it is not special cased, but is supposed to work universally. That it does not work for Nick is probably a bug, not a sensible and thought-out limitation. It can be very handy for Metaprogramming, this needs to get fixed at some point. Nick: Can you try to deduce a minimal test case? (Or provide the full listing of the code?) Timon
Jun 01 2011
next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 01 Jun 2011 10:32:10 -0400, Timon Gehr <timon.gehr gmx.ch> wrote:

 Steven Schveighoffer wrote:
 I think there are certain special situations where you can use
 typeof(this).  For example, as the return type for a static method.

 *looks for doc*  Couldn't find any documentation on it...

 It's somewhat like static this, which is inflexible in how you write it.

 -Steve
It is not documented in detail but it is there =). See: http://www.digitalmars.com/d/2.0/declaration.html "1. typeof(this) will generate the type of what this would be in a non-static member function, even if not in a member function. "
D'oh! I must have skipped over that page.
 Therefore it is not special cased, but is supposed to work universally.

 That it does not work for Nick is probably a bug, not a sensible and  
 thought-out
 limitation. It can be very handy for Metaprogramming, this needs to get  
 fixed at
 some point.

  Nick: Can you try to deduce a minimal test case? (Or provide the full  
 listing of
 the code?)
I agree with all of this, I think it should work, judging from that documentation. -Steve
Jun 01 2011
prev sibling parent "Nick Sabalausky" <a a.a> writes:
"Timon Gehr" <timon.gehr gmx.ch> wrote in message 
news:is5iha$1e2k$1 digitalmars.com...
 It is not documented in detail but it is there =).
 See: http://www.digitalmars.com/d/2.0/declaration.html
 "1. typeof(this) will generate the type of what this would be in a 
 non-static
 member function, even if not in a member function. "

 Therefore it is not special cased, but is supposed to work universally.

 That it does not work for Nick is probably a bug, not a sensible and 
 thought-out
 limitation. It can be very handy for Metaprogramming, this needs to get 
 fixed at
 some point.

  Nick: Can you try to deduce a minimal test case? (Or provide the full 
 listing of
 the code?)
Done: http://d.puremagic.com/issues/show_bug.cgi?id=6087
Jun 01 2011
prev sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Timon Gehr" <timon.gehr gmx.ch> wrote in message 
news:is2lts$2fcn$1 digitalmars.com...
 bearophile wrote:
 ...
 A shorter way to write it:

 void addGizmos(int numPorts, bool isSpinnable, int numGizmos) {
     foreach (np; TypeTuple!(1, 2, 3, 5, 10))
         if (numPorts == np) {
             foreach (b; TypeTuple!(true, false))
                 if (isSpinnable == b)
                     addGizmosTo!(np, b)(numGizmos);
             return;
         }

     throw new Exception(text(numPorts) ~ "-port Gizmo not supported.");
 }

 Bye,
 bearophile
Nice, but isSpinnable is always checked twice with your approach. Better: void addGizmos(int numPorts, bool isSpinnable, int numGizmos) { foreach (np; TypeTuple!(1, 2, 3, 5, 10)) if (numPorts == np) { if (isSpinnable) addGizmosTo!(np, true)(numGizmos); else addGizmosTo!(np, false)(numGizmos); return; } throw new Exception(text(numPorts) ~ "-port Gizmo not supported."); }
I love this idea. I had no idea you could use TypeTuple for values. But it doesn't seem to be working in ths particular case. On the line that tries to call 'addGizmosTo' I get this compiler error: Error: template instance cannot use local 'np' as parameter to non-global template addGizmosTo(int numPorts,bool isSpinnable)
May 31 2011
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
Nick Sabalausky wrote:
"Timon Gehr" <timon.gehr gmx.ch> wrote in message
news:is2lts$2fcn$1 digitalmars.com...
 bearophile wrote:
 ...
 A shorter way to write it:

 void addGizmos(int numPorts, bool isSpinnable, int numGizmos) {
     foreach (np; TypeTuple!(1, 2, 3, 5, 10))
         if (numPorts == np) {
             foreach (b; TypeTuple!(true, false))
                 if (isSpinnable == b)
                     addGizmosTo!(np, b)(numGizmos);
             return;
         }

     throw new Exception(text(numPorts) ~ "-port Gizmo not supported.");
 }

 Bye,
 bearophile
Nice, but isSpinnable is always checked twice with your approach. Better: void addGizmos(int numPorts, bool isSpinnable, int numGizmos) { foreach (np; TypeTuple!(1, 2, 3, 5, 10)) if (numPorts == np) { if (isSpinnable) addGizmosTo!(np, true)(numGizmos); else addGizmosTo!(np, false)(numGizmos); return; } throw new Exception(text(numPorts) ~ "-port Gizmo not supported."); }
I love this idea. I had no idea you could use TypeTuple for values. But it doesn't seem to be working in ths particular case. On the line that tries to call 'addGizmosTo' I get this compiler error: Error: template instance cannot use local 'np' as parameter to non-global template addGizmosTo(int numPorts,bool isSpinnable)
Interesting. I suspect that is a bug. Can somebody shed light on what the purpose of that Error message is? Timon
May 31 2011
prev sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Nick Sabalausky:

 Error: template instance cannot use local 'np' as parameter to non-global 
 template addGizmosTo(int numPorts,bool isSpinnable)
Are you able to reduce this to a minimal test case? Bye, bearophile
May 31 2011
parent reply "Nick Sabalausky" <a a.a> writes:
"bearophile" <bearophileHUGS lycos.com> wrote in message 
news:is45u7$21vq$1 digitalmars.com...
 Nick Sabalausky:

 Error: template instance cannot use local 'np' as parameter to non-global
 template addGizmosTo(int numPorts,bool isSpinnable)
Are you able to reduce this to a minimal test case?
If it is indeed a bug then I'll try. But the fact that there's an error message for it seems to indicate this is intended for some reason. After all, addGizmosTo *is* a non-global template, just like the message says. And 'np' shouldn't be visible outside the function it's in, ie, it's local.
May 31 2011
parent Timon Gehr <timon.gehr gmx.ch> writes:
Nick Sabalausky wrote:
 "bearophile" <bearophileHUGS lycos.com> wrote in message
 news:is45u7$21vq$1 digitalmars.com...
 Nick Sabalausky:

 Error: template instance cannot use local 'np' as parameter to non-global
 template addGizmosTo(int numPorts,bool isSpinnable)
Are you able to reduce this to a minimal test case?
If it is indeed a bug then I'll try. But the fact that there's an error message for it seems to indicate this is intended for some reason. After all, addGizmosTo *is* a non-global template, just like the message says. And 'np' shouldn't be visible outside the function it's in, ie, it's local.
'np' is just an integer literal at the point of instantiation. Would you want to not be able to call a function with local variables as parameters either? Eg: int main(){ int foo(int){...} foreach(np;[1,2,3,4,5]) foo(np); } If the bug was there for runtime foreach too, this would print Error: function call cannot use local 'np' as parameter to non-global function foo. This would also be a fit for It is certainly a bug, there is no reason why it should not work. (an integer literal is not bound to a scope). Minimal test case: import std.typetuple; void main(){ int foo(int x)(){return x;} foreach(i;TypeTuple!(0)) foo!(i); } Bug report: http://d.puremagic.com/issues/show_bug.cgi?id=6084 Probably, the Error is intended for the following case: int bar(int x)(){return x;} void main(){ immutable int i=0; int foo(int x)(){return x;} foo!i; //error bar!i; //ok } Is there any reason why this should not work? Is it just an implementation issue? (I have heard of immutable compile-time values not yet working properly.) Workaround for the bug: import std.typetuple; void main(){ int foo(int x)(){return x;} foreach(_i;TypeTuple!(0)){ enum i=_i; foo!i; } } I think it should be possible to fix it for TypeTuple foreach by having the iteration variable be enum. I'll have a look at the compiler. Timon
Jun 01 2011
prev sibling parent reply Ary Manzana <ary esperanto.org.ar> writes:
On 5/31/11 6:05 PM, bearophile wrote:
 Nick Sabalausky:

 http://www.semitwist.com/articles/EfficientAndFlexible/SinglePage/
Regarding your addGizmos() in ex6_meta_flex3_runtimeToCompileTime1.d: void addGizmos(int numPorts, bool isSpinnable, int numGizmos) { // Dispatch to correct version of addGizmosTo. // Effectively converts a runtime value to compile-time. if (numPorts == 1) { if (isSpinnable) addGizmosTo!(1, true )(numGizmos); else addGizmosTo!(1, false)(numGizmos); } else if (numPorts == 2) { if (isSpinnable) addGizmosTo!(2, true )(numGizmos); else addGizmosTo!(2, false)(numGizmos); } else if (numPorts == 3) { if (isSpinnable) addGizmosTo!(3, true )(numGizmos); else addGizmosTo!(3, false)(numGizmos); } else if (numPorts == 5) { if (isSpinnable) addGizmosTo!(5, true )(numGizmos); else addGizmosTo!(5, false)(numGizmos); } else if (numPorts == 10) { if (isSpinnable) addGizmosTo!(10, true )(numGizmos); else addGizmosTo!(10, false)(numGizmos); } else throw new Exception(to!string(numPorts)~"-port Gizmo not supported."); } A shorter way to write it: void addGizmos(int numPorts, bool isSpinnable, int numGizmos) { foreach (np; TypeTuple!(1, 2, 3, 5, 10)) if (numPorts == np) { foreach (b; TypeTuple!(true, false)) if (isSpinnable == b) addGizmosTo!(np, b)(numGizmos); return; } throw new Exception(text(numPorts) ~ "-port Gizmo not supported."); } Bye, bearophile
Why you need a type tuple? Can't you do: foreach(np; [1, 2, 3, 5, 10])
May 31 2011
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
Ary Manzana wrote:
 Why you need a type tuple? Can't you do:

 foreach(np; [1, 2, 3, 5, 10])
That is a runtime foreach, so no. If the argument is a TypeTuple, the compiler evaluates the foreach as a "static foreach", effectively duplicating all code in its body and filling in the constants/types in the tuple. I would like an explicit "static foreach" better though. Timon
May 31 2011
parent reply bearophile <bearophileHUGS lycos.com> writes:
Timon Gehr:

 Nice, but isSpinnable is always checked twice with your approach.
Right. But isn't the compiler able to optimize away this inefficiency?
 I would like an explicit "static foreach" better though.
See: http://d.puremagic.com/issues/show_bug.cgi?id=4085 Bye, bearophile
May 31 2011
parent Timon Gehr <timon.gehr gmx.ch> writes:
 Timon Gehr:

 Nice, but isSpinnable is always checked twice with your approach.
Right. But isn't the compiler able to optimize away this inefficiency?
Nope. You don't get a guarantee from the language that your code will be optimized in a certain way. That said, dmd/gdc are _not_ able to do it sensibly for the most trivial case: if(x) writeln("x"); if(!x) writeln("!x"); results in the following when compiled with dmd -O -release -inline. cmp dword ptr [ebp-8], 0 ; first check jz short loc_8096042 ; first check push dword ptr ds:_TMP1+4 push dword ptr ds:_TMP1 call _D3std5stdio16__T7writelnTAyaZ7writelnFAyaZv loc_8096042: cmp dword ptr [ebp-8], 0 ; second check jnz short loc_8096059 ; second check push dword ptr ds:_TMP2+4 push dword ptr ds:_TMP2 call _D3std5stdio16__T7writelnTAyaZ7writelnFAyaZv loc_8096059: ; function epilogue comes here. With gdmd -O -release -inline: mov ecx, [esp+20h+var_4] ; first check test ecx, ecx ; first check jnz short loc_804AE98 ; first check loc_804AE7D: mov [esp+20h+var_20], 2 mov [esp+20h+var_1C], offset unk_80A3448 ;"!x" call _D3std5stdio16__T7writelnTAyaZ7writelnFAyaZv ; function epilogue comes here loc_804AE98: mov [esp+20h+var_20], 1 mov [esp+20h+var_1C], offset asc_80A3446 ; "x" call _D3std5stdio16__T7writelnTAyaZ7writelnFAyaZv mov edx, [esp+20h+var_4] ; second check (nonsense) test edx, edx ; second check (nonsense) jz short loc_804AE7D ; second check (nonsense) ; function epilogue comes here This is _really_ silly oO. gdc was almost there. It clearly had to understand that x and !x are mutually exclusive to generate such code (it _reordered_ the two checks =DD), but then it created 3 totally nonsensical instructions for a totally redundant second check nevertheless. It still gets some credit for duplicating the function epilogue instead of adding another jump. Compilers are not magical, they are stupid programs that cannot replace your insight. ;)
 I would like an explicit "static foreach" better though.
See: http://d.puremagic.com/issues/show_bug.cgi?id=4085 Bye, bearophile
Thanks for the information. I already suspected it to be a matter of implementation. Timon
May 31 2011
prev sibling parent "Nick Sabalausky" <a a.a> writes:
"Nick Sabalausky" <a a.a> wrote in message 
news:is22gk$1v03$1 digitalmars.com...
 Getting in just under the wire here. I seem to have misjudged the scope of 
 my topic, it ended up a bit large... Anyway, here's my entry:

 http://www.semitwist.com/articles/EfficientAndFlexible/SinglePage/
Thanks everyone for all the great suggestions. With 10 minutes now until midnight GMT, I've incorporated all the changes that I was able to get working.
May 31 2011