diff --git a/hands-on_dlang.md b/hands-on_dlang.md index baeb8d9..e798c72 100644 --- a/hands-on_dlang.md +++ b/hands-on_dlang.md @@ -545,7 +545,7 @@ flag `--boundcheck=off`. #### Static arrays Static arrays are stored on he stack or in static memory, depending on where -they are defined. They have a fixed, compile-time known length. The length is +they are defined. They have a fixed, compile time known length. The length is part of the type: ```D @@ -1357,8 +1357,8 @@ the `-cov` flag. When using DUB, just add the flag `--coverage`. ### String mixins -The mixin expression takes an arbitrary string and compiles it and generates instructions accordingly. This is a compile-time feature, so ths string needs -to be known at compile-time. +The mixin expression takes an arbitrary string and compiles it and generates instructions accordingly. This is a compile time feature, so ths string needs +to be known at compile time. ```D mixin("int b = 5"); // compiles just fine @@ -1369,7 +1369,7 @@ mixin(compileTimeKnownString); // so does this assert(c == 5); immutable runTimeString = q{int c =5;}; -mixin(runTimeString); // compile error, runTimeString is not known at compile-time +mixin(runTimeString); // compile error, runTimeString is not known at compile time ``` ### Compile Time Function Evaluation (CTFE) @@ -1412,4 +1412,98 @@ void main() { writeln("The sqrt of compile time 4 = ", cn); } +``` + +### Conditional compilation + +D has several methods of conditional compilation which can be used for code +generation. D’s traits and the module `std.traits` contain many usefull tools +which can be used with the following constructs. + +#### `static if` & `is` + +`static if` conditionally compiles a code block based on a condition that can be +evaluated at compile time: + +```D +foo(int x)() { // x is a template parameter and thus known at compile time + static if(x == 0) + writeln("x is 0"); + else + writeln() +} +``` + +The `is` expression is used to check for valid types and to compare types: + +```D +foo(T)() { + static if(is(T)) { + writeln("T is a valid type"); + } + static if(is(T == int)) { + writeln("T is int"); + } + static if(is(T : int)) { + writeln("T implicitly converts to int"); + } +} +``` + +#### `static foreach` + +`static foreach` allows you to iterate at compile time in order to generate +code. It is best explained by an example: The code + +```D +import std.stdio; + +void main() { + static foreach(element; ["foo", "bar", "baz"]) { + writeln(element); + } +} +``` + +effectively lowers to + +```D +import std.stdio; + +void main() { + writeln("foo"); + writeln("bar"); + writeln("baz"); +} +``` + +which means there is no loop at runtime. + +#### Template constraints + +A template may be defined with any number of constraints that enforce some +properties of the template parameters: + +```D +void foo(T)(T value) + if (is(T : long)) { // foo!T only valid if T implicitly converts to long +} + +foo(42); // compiles, 42 is of type int which implicitly converts to long +foo("someString"); // compile error, strings do not implicitly convert to long +``` + +```D +void bar(T)(T value) + if (__traits(compiles, {T t = T.init; t.fly();})) { // bar!T only valid if we can initialize T and T has a method called fly which takes no parameters +} + +struct MyStruct { + void fly() {} +} + +MyStruct myStruct; + +bar(myStruct); // compiles +bar(42); // compile error ``` \ No newline at end of file