Conditional compilation is the process of selecting which code to compile and which code to not compile similar to the #if / #else / #endif in C and C++. Any statement that is not compiled in still must be syntactically correct.
Conditional compilation involves condition checks that are evaluable at compile time. Runtime conditional statements like if, for, while are not conditional compilation features. The following features of D are meant for conditional compilation −
The debug is useful during program development. The expressions and statements that are marked as debug are compiled into the program only when the -debug compiler switch is enabled.
debug a_conditionally_compiled_expression; debug { // ... conditionally compiled code ... } else { // ... code that is compiled otherwise ... }
The else clause is optional. Both the single expression and the code block above are compiled only when the -debug compiler switch is enabled.
Instead of being removed altogether, the lines can be marked as debug instead.
debug writefln("%s debug only statement", value);
Such lines are included in the program only when the -debug compiler switch is enabled.
dmd test.d -oftest -w -debug
The debug statements can be given names (tags) to be included in the program selectively.
debug(mytag) writefln("%s not found", value);
Such lines are included in the program only when the -debug compiler switch is enabled.
dmd test.d -oftest -w -debug = mytag
The debug blocks can have tags as well.
debug(mytag) { // }
It is possible to enable more than one debug tag at a time.
dmd test.d -oftest -w -debug = mytag1 -debug = mytag2
Sometimes it is more useful to associate debug statements by numerical levels. Increasing levels can provide more detailed information.
import std.stdio; void myFunction() { debug(1) writeln("debug1"); debug(2) writeln("debug2"); } void main() { myFunction(); }
The debug expressions and blocks that are lower than or equal to the specified level would be compiled.
$ dmd test.d -oftest -w -debug = 1 $ ./test debug1
Version is similar to debug and is used in the same way. The else clause is optional. Although version works essentially the same as debug, having separate keywords helps distinguish their unrelated uses. As with debug, more than one version can be enabled.
import std.stdio; void myFunction() { version(1) writeln("version1"); version(2) writeln("version2"); } void main() { myFunction(); }
The debug expressions and blocks that are lower than or equal to the specified level would be compiled.
$ dmd test.d -oftest -w -version = 1 $ ./test version1
Static if is the compile time equivalent of the if statement. Just like the if statement, static if takes a logical expression and evaluates it. Unlike the if statement, static if is not about execution flow; rather, it determines whether a piece of code should be included in the program or not.
The if expression is unrelated to the is operator that we have seen earlier, both syntactically and semantically. It is evaluated at compile time. It produces an int value, either 0 or 1; depending on the expression specified in parentheses. Although the expression that it takes is not a logical expression, the is expression itself is used as a compile time logical expression. It is especially useful in static if conditionals and template constraints.
import std.stdio; enum Days { sun, mon, tue, wed, thu, fri, sat }; void myFunction(T)(T mytemplate) { static if (is (T == class)) { writeln("This is a class type"); } else static if (is (T == enum)) { writeln("This is an enum type"); } } void main() { Days day; myFunction(day); }
When we compile and run we will get some output as follows.
This is an enum type