digitalmars.D.bugs - [Issue 16330] New: Expansion of code (static foreach, templates) is
- via Digitalmars-d-bugs (89/89) Jul 28 2016 https://issues.dlang.org/show_bug.cgi?id=16330
https://issues.dlang.org/show_bug.cgi?id=16330 Issue ID: 16330 Summary: Expansion of code (static foreach, templates) is too slow Product: D Version: D2 Hardware: All OS: All Status: NEW Severity: normal Priority: P1 Component: dmd Assignee: nobody puremagic.com Reporter: bugzilla digitalmars.com Ethan Watson writes: Expansion of code (static foreach, templates) is slow to the point where string mixins are a legitimate compile-time optimisation Take an example of whittling down a tuple/variable argument list. Doing it recursively would look something like this: template SomeEliminator( Symbols... ) { static if( Symbols.length >= 1 ) { static if( SomeCondition!( Symbol[ 0 ] ) ) { alias SomeEliminator = TypeTuple!( Symbol[ 0 ], Symbols[ 1 .. $ ] ); } else { alias SomeEliminator = TypeTuple!( Symbols[ 1 .. $ ] ); } } else { alias SomeEliminator = TypeTuple!( ); } } Okay, that works, but the template expansion is a killer on compile-time performance. It's legitimately far quicker on the compiler to do this: template SomeEliminator( Symbols... ) { string SymbolSelector() { string[] strOutputs; foreach( iIndex, Symbol; Symbols ) { static if( SomeCondition!( Symbol ) ) { strOutputs ~= "Symbols[ " ~ iIndex.stringof ~ " ]"; } } return strOutputs.joinWith( ", " ); } mixin( "alias SomeEliminator = TypeTuple!( " ~ SymbolSelector() ~ " );" ); } With just a small codebase that I'm working on here, it chops seconds off the compile time. Of course, maybe there's something I'm missing here about variable parameter parsing and doing it without a mixin is quite possible and just as quick as the mixin, but that would make it the third method I know of to achieve the same effect. The idiomatic way of doing this without mixins should at least be defined, and optimised at the compiler level so that people don't get punished for writing natural D code. Then there was this one that I came across: outofswitch: switch( symbolName ) { foreach( Variable; VariablesOf!( SearchType ) ) { case Variable.Name: doSomething!( Variable.Type )(); break outofswitch; } default: writeln( symbolName, " was not found!" ); break; } This caused compile time to blow way out. How far out? By rewriting it like this, I cut compile times in half (at that point, from 10 seconds to 5): switch( symbolName ) { mixin( generateSwitchFor!( SearchType )() ); default: writeln( symbolName, " was not found!" ); break; } Now, I love mixins, both template form and string form. The binding system uses them extensively. But mixins like this are effectively a hack. Anytime I have to break out a mixin because my compile time doubled from a seemingly simple piece of code is not good. --
Jul 28 2016