$(DDOC $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE ) $(SPEC_S Conditional Compilation, $(DDOC_BLANKLINE ) $(HEADERNAV_TOC $(HEADERNAV_ITEM version, Version Condition) $(HEADERNAV_SUBITEMS version-specification, Version Specification, $(HEADERNAV_ITEM predefined-versions, Predefined Versions) ) $(HEADERNAV_SUBITEMS debug, Debug Condition, $(HEADERNAV_ITEM DebugStatement, Debug Statement) ) $(HEADERNAV_ITEM debug_specification, Debug Specification) $(HEADERNAV_ITEM staticif, Static If Condition) $(HEADERNAV_SUBITEMS staticforeach, Static Foreach, $(HEADERNAV_ITEM break-continue, break and continue) ) $(HEADERNAV_ITEM static-assert, Static Assert) ) $(DDOC_BLANKLINE ) $(P $(I Conditional compilation) is the process of selecting which code to compile and which code to not compile. ) $(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME ConditionalDeclaration): $(GLINK Condition) $(GLINK2 attribute, DeclarationBlock) $(GLINK Condition) $(GLINK2 attribute, DeclarationBlock) $(D else) $(GLINK2 attribute, DeclarationBlock) $(GLINK Condition) $(D :) $(GLINK2 module, DeclDefs)$(OPT ) $(GLINK Condition) $(GLINK2 attribute, DeclarationBlock) $(D else) $(D :) $(GLINK2 module, DeclDefs)$(OPT ) $(DDOC_BLANKLINE ) $(GNAME ConditionalStatement): $(GLINK Condition) $(GLINK2 statement, NoScopeNonEmptyStatement) $(GLINK Condition) $(GLINK2 statement, NoScopeNonEmptyStatement) $(D else) $(GLINK2 statement, NoScopeNonEmptyStatement) ) $(DDOC_BLANKLINE ) $(P If the $(GLINK Condition) is satisfied, then the following $(I DeclarationBlock) or $(I Statement) is compiled in. If it is not satisfied, the $(I DeclarationBlock) or $(I Statement) after the optional $(CODE else) is compiled in. ) $(DDOC_BLANKLINE ) $(P Any $(I DeclarationBlock) or $(I Statement) that is not compiled in still must be syntactically correct. ) $(DDOC_BLANKLINE ) $(P No new scope is introduced, even if the $(I DeclarationBlock) or $(I Statement) is enclosed by $(CODE { }). ) $(DDOC_BLANKLINE ) $(P $(I ConditionalDeclaration)s and $(I ConditionalStatement)s can be nested. ) $(DDOC_BLANKLINE ) $(P The $(GLINK StaticAssert) can be used to issue errors at compilation time for branches of the conditional compilation that are errors. ) $(DDOC_BLANKLINE ) $(P $(I Condition) comes in the following forms: ) $(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME Condition): $(GLINK VersionCondition) $(GLINK DebugCondition) $(GLINK StaticIfCondition) ) $(DDOC_BLANKLINE )

$(LNAME2 version, Version Condition)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME VersionCondition): $(D version $(LPAREN)) $(GLINK_LEX Identifier) $(D $(RPAREN )) $(D version $(LPAREN)) $(D unittest) $(D $(RPAREN )) $(D version $(LPAREN)) $(D assert) $(D $(RPAREN )) ) $(DDOC_BLANKLINE ) $(P Versions enable multiple versions of a module to be implemented with a single source file. ) $(DDOC_BLANKLINE ) $(P The $(I VersionCondition) is satisfied if $(I Identifier) matches a $(I version identifier). ) $(DDOC_BLANKLINE ) $(P The $(I version identifier) can be set on the command line by the $(D -version) switch or in the module itself with a $(GLINK VersionSpecification), or they can be predefined by the compiler. ) $(DDOC_BLANKLINE ) $(P Version identifiers are in their own unique name space, they do not conflict with debug identifiers or other symbols in the module. Version identifiers defined in one module have no influence over other imported modules. ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD int) k; $(D_KEYWORD version) (Demo) $(D_COMMENT // compile in this code block for the demo version ){ $(D_KEYWORD int) i; $(D_KEYWORD int) k; $(D_COMMENT // error, k already defined ) i = 3; } x = i; $(D_COMMENT // uses the i declared above )) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD version) (X86) { ... $(D_COMMENT // implement custom inline assembler version )} $(D_KEYWORD else) { ... $(D_COMMENT // use default, but slow, version )} ) $(DDOC_BLANKLINE ) $(P The $(D version(unittest)) is satisfied if and only if the code is compiled with unit tests enabled (the $(DDSUBLINK dmd, switch-unittest, $(TT -unittest)) option on $(TT dmd)). ) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LEGACY_LNAME2 VersionSpecification, version-specification, Version Specification)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME VersionSpecification): $(D version =) $(GLINK_LEX Identifier) $(D ;) ) $(DDOC_BLANKLINE ) $(P The version specification makes it straightforward to group a set of features under one major version, for example: ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD version) (ProfessionalEdition) { $(D_KEYWORD version) = FeatureA; $(D_KEYWORD version) = FeatureB; $(D_KEYWORD version) = FeatureC; } $(D_KEYWORD version) (HomeEdition) { $(D_KEYWORD version) = FeatureA; } ... $(D_KEYWORD version) (FeatureB) { ... implement Feature B ... } ) $(DDOC_BLANKLINE ) $(P Version identifiers or levels may not be forward referenced: ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD version) (Foo) { $(D_KEYWORD int) x; } $(D_KEYWORD version) = Foo; $(D_COMMENT // error, Foo already used )) $(P $(I VersionSpecification)s may only appear at module scope.) $(DDOC_BLANKLINE ) $(P While the debug and version conditions superficially behave the same, they are intended for very different purposes. Debug statements are for adding debug code that is removed for the release version. Version statements are to aid in portability and multiple release versions. ) $(DDOC_BLANKLINE ) $(P Here's an example of a $(I full) version as opposed to a $(I demo) version:) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD class) Foo { $(D_KEYWORD int) a, b; $(D_KEYWORD version)(full) { $(D_KEYWORD int) extrafunctionality() { ... $(D_KEYWORD return) 1; $(D_COMMENT // extra functionality is supported ) } } $(D_KEYWORD else) $(D_COMMENT // demo ) { $(D_KEYWORD int) extrafunctionality() { $(D_KEYWORD return) 0; $(D_COMMENT // extra functionality is not supported ) } } } ) $(DDOC_BLANKLINE ) $(P Various different version builds can be built with a parameter to version: ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD version)($(CODE_HIGHLIGHT identifier)) $(D_COMMENT // add in version code if version ) $(D_COMMENT // keyword is identifier ){ ... $(D_KEYWORD version) code ... } ) $(DDOC_BLANKLINE ) $(P This is presumably set by the command line as $(D -version=identifier). ) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LEGACY_LNAME2 PredefinedVersions, predefined-versions, Predefined Versions)

$(DDOC_BLANKLINE ) $(P Several environmental version identifiers and identifier name spaces are predefined for consistent usage. Version identifiers do not conflict with other identifiers in the code, they are in a separate name space. Predefined version identifiers are global, i.e. they apply to all modules being compiled and imported. ) $(DDOC_BLANKLINE ) $(LONGTABLE_2COLS 0.6, Predefined Version Identifiers, Version Identifier, Description, $(TROW $(ARGS $(D DigitalMars)) , $(ARGS DMD (Digital Mars D) is the compiler)) $(TROW $(ARGS $(D GNU)) , $(ARGS GDC (GNU D Compiler) is the compiler)) $(TROW $(ARGS $(D LDC)) , $(ARGS LDC (LLVM D Compiler) is the compiler)) $(TROW $(ARGS $(D SDC)) , $(ARGS SDC (Stupid D Compiler) is the compiler)) $(TROW $(ARGS $(D Windows)) , $(ARGS Microsoft Windows systems)) $(TROW $(ARGS $(D Win32)) , $(ARGS Microsoft 32-bit Windows systems)) $(TROW $(ARGS $(D Win64)) , $(ARGS Microsoft 64-bit Windows systems)) $(TROW $(ARGS $(D linux)) , $(ARGS All Linux systems)) $(TROW $(ARGS $(D OSX)) , $(ARGS macOS)) $(TROW $(ARGS $(D iOS)) , $(ARGS iOS)) $(TROW $(ARGS $(D TVOS)) , $(ARGS tvOS)) $(TROW $(ARGS $(D WatchOS)) , $(ARGS watchOS)) $(TROW $(ARGS $(D VisionOS)) , $(ARGS visionOS)) $(TROW $(ARGS $(D FreeBSD)) , $(ARGS FreeBSD)) $(TROW $(ARGS $(D OpenBSD)) , $(ARGS OpenBSD)) $(TROW $(ARGS $(D NetBSD)) , $(ARGS NetBSD)) $(TROW $(ARGS $(D DragonFlyBSD)) , $(ARGS DragonFlyBSD)) $(TROW $(ARGS $(D BSD)) , $(ARGS All other BSDs)) $(TROW $(ARGS $(D Solaris)) , $(ARGS Solaris)) $(TROW $(ARGS $(D Posix)) , $(ARGS All POSIX systems (includes Linux, FreeBSD, OS X, Solaris, etc.))) $(TROW $(ARGS $(D AIX)) , $(ARGS IBM Advanced Interactive eXecutive OS)) $(TROW $(ARGS $(D Haiku)) , $(ARGS The Haiku operating system)) $(TROW $(ARGS $(D SkyOS)) , $(ARGS The SkyOS operating system)) $(TROW $(ARGS $(D SysV3)) , $(ARGS System V Release 3)) $(TROW $(ARGS $(D SysV4)) , $(ARGS System V Release 4)) $(TROW $(ARGS $(D Hurd)) , $(ARGS GNU Hurd)) $(TROW $(ARGS $(D Android)) , $(ARGS The Android platform)) $(TROW $(ARGS $(D Emscripten)) , $(ARGS The Emscripten platform)) $(TROW $(ARGS $(D PlayStation)) , $(ARGS The PlayStation platform)) $(TROW $(ARGS $(D PlayStation4)) , $(ARGS The PlayStation 4 platform)) $(TROW $(ARGS $(D Cygwin)) , $(ARGS The Cygwin environment)) $(TROW $(ARGS $(D MinGW)) , $(ARGS The MinGW environment)) $(TROW $(ARGS $(D FreeStanding)) , $(ARGS An environment without an operating system (such as Bare-metal targets))) $(TROW $(ARGS $(D CRuntime_Bionic)) , $(ARGS Bionic C runtime)) $(TROW $(ARGS $(D CRuntime_DigitalMars)) , $(ARGS DigitalMars C runtime)) $(TROW $(ARGS $(D CRuntime_Glibc)) , $(ARGS Glibc C runtime)) $(TROW $(ARGS $(D CRuntime_Microsoft)) , $(ARGS Microsoft C runtime)) $(TROW $(ARGS $(D CRuntime_Musl)) , $(ARGS musl C runtime)) $(TROW $(ARGS $(D CRuntime_Newlib)) , $(ARGS newlib C runtime)) $(TROW $(ARGS $(D CRuntime_UClibc)) , $(ARGS uClibc C runtime)) $(TROW $(ARGS $(D CRuntime_WASI)) , $(ARGS WASI C runtime)) $(TROW $(ARGS $(D CppRuntime_Clang)) , $(ARGS Clang Cpp runtime)) $(TROW $(ARGS $(D CppRuntime_DigitalMars)) , $(ARGS DigitalMars Cpp runtime)) $(TROW $(ARGS $(D CppRuntime_Gcc)) , $(ARGS Gcc Cpp runtime)) $(TROW $(ARGS $(D CppRuntime_Microsoft)) , $(ARGS Microsoft Cpp runtime)) $(TROW $(ARGS $(D CppRuntime_Sun)) , $(ARGS Sun Cpp runtime)) $(TROW $(ARGS $(D X86)) , $(ARGS Intel and AMD 32-bit processors)) $(TROW $(ARGS $(D X86_64)) , $(ARGS Intel and AMD 64-bit processors)) $(TROW $(ARGS $(D ARM)) , $(ARGS The ARM architecture (32-bit) (AArch32 et al))) $(TROW $(ARGS $(D ARM_Thumb)) , $(ARGS ARM in any Thumb mode)) $(TROW $(ARGS $(D ARM_SoftFloat)) , $(ARGS The ARM $(D soft) floating point ABI)) $(TROW $(ARGS $(D ARM_SoftFP)) , $(ARGS The ARM $(D softfp) floating point ABI)) $(TROW $(ARGS $(D ARM_HardFloat)) , $(ARGS The ARM $(D hardfp) floating point ABI)) $(TROW $(ARGS $(D AArch64)) , $(ARGS The Advanced RISC Machine architecture (64-bit))) $(TROW $(ARGS $(D AsmJS)) , $(ARGS The asm.js intermediate programming language)) $(TROW $(ARGS $(D AVR)) , $(ARGS 8-bit Atmel AVR Microcontrollers)) $(TROW $(ARGS $(D Epiphany)) , $(ARGS The Epiphany architecture)) $(TROW $(ARGS $(D PPC)) , $(ARGS The PowerPC architecture, 32-bit)) $(TROW $(ARGS $(D PPC_SoftFloat)) , $(ARGS The PowerPC soft float ABI)) $(TROW $(ARGS $(D PPC_HardFloat)) , $(ARGS The PowerPC hard float ABI)) $(TROW $(ARGS $(D PPC64)) , $(ARGS The PowerPC architecture, 64-bit)) $(TROW $(ARGS $(D IA64)) , $(ARGS The Itanium architecture (64-bit))) $(TROW $(ARGS $(D MIPS32)) , $(ARGS The MIPS architecture, 32-bit)) $(TROW $(ARGS $(D MIPS64)) , $(ARGS The MIPS architecture, 64-bit)) $(TROW $(ARGS $(D MIPS_O32)) , $(ARGS The MIPS O32 ABI)) $(TROW $(ARGS $(D MIPS_N32)) , $(ARGS The MIPS N32 ABI)) $(TROW $(ARGS $(D MIPS_O64)) , $(ARGS The MIPS O64 ABI)) $(TROW $(ARGS $(D MIPS_N64)) , $(ARGS The MIPS N64 ABI)) $(TROW $(ARGS $(D MIPS_EABI)) , $(ARGS The MIPS EABI)) $(TROW $(ARGS $(D MIPS_SoftFloat)) , $(ARGS The MIPS $(D soft-float) ABI)) $(TROW $(ARGS $(D MIPS_HardFloat)) , $(ARGS The MIPS $(D hard-float) ABI)) $(TROW $(ARGS $(D MSP430)) , $(ARGS The MSP430 architecture)) $(TROW $(ARGS $(D NVPTX)) , $(ARGS The Nvidia Parallel Thread Execution (PTX) architecture, 32-bit)) $(TROW $(ARGS $(D NVPTX64)) , $(ARGS The Nvidia Parallel Thread Execution (PTX) architecture, 64-bit)) $(TROW $(ARGS $(D RISCV32)) , $(ARGS The RISC-V architecture, 32-bit)) $(TROW $(ARGS $(D RISCV64)) , $(ARGS The RISC-V architecture, 64-bit)) $(TROW $(ARGS $(D SPARC)) , $(ARGS The SPARC architecture, 32-bit)) $(TROW $(ARGS $(D SPARC_V8Plus)) , $(ARGS The SPARC v8+ ABI)) $(TROW $(ARGS $(D SPARC_SoftFloat)) , $(ARGS The SPARC soft float ABI)) $(TROW $(ARGS $(D SPARC_HardFloat)) , $(ARGS The SPARC hard float ABI)) $(TROW $(ARGS $(D SPARC64)) , $(ARGS The SPARC architecture, 64-bit)) $(TROW $(ARGS $(D S390)) , $(ARGS The System/390 architecture, 32-bit)) $(TROW $(ARGS $(D SystemZ)) , $(ARGS The System Z architecture, 64-bit)) $(TROW $(ARGS $(D HPPA)) , $(ARGS The HP PA-RISC architecture, 32-bit)) $(TROW $(ARGS $(D HPPA64)) , $(ARGS The HP PA-RISC architecture, 64-bit)) $(TROW $(ARGS $(D SH)) , $(ARGS The SuperH architecture, 32-bit)) $(TROW $(ARGS $(D WebAssembly)) , $(ARGS The WebAssembly virtual ISA $(LPAREN)instruction set architecture$(RPAREN ), 32-bit)) $(TROW $(ARGS $(D WASI)) , $(ARGS The WebAssembly System Interface)) $(TROW $(ARGS $(D Alpha)) , $(ARGS The Alpha architecture)) $(TROW $(ARGS $(D Alpha_SoftFloat)) , $(ARGS The Alpha soft float ABI)) $(TROW $(ARGS $(D Alpha_HardFloat)) , $(ARGS The Alpha hard float ABI)) $(TROW $(ARGS $(D LittleEndian)) , $(ARGS Byte order, least significant first)) $(TROW $(ARGS $(D BigEndian)) , $(ARGS Byte order, most significant first)) $(TROW $(ARGS $(D ELFv1)) , $(ARGS The Executable and Linkable Format v1)) $(TROW $(ARGS $(D ELFv2)) , $(ARGS The Executable and Linkable Format v2)) $(TROW $(ARGS $(D D_BetterC)) , $(ARGS $(DDLINK spec/betterc, D as Better C, D as Better C) code (command line switch $(DDSUBLINK dmd, switch-betterC, $(TT -betterC))) is being generated)) $(TROW $(ARGS $(D D_Exceptions)) , $(ARGS Exception handling is supported. Evaluates to false when compiling with command line switch $(DDSUBLINK dmd, switch-betterC, $(TT -betterC)))) $(TROW $(ARGS $(D D_ModuleInfo)) , $(ARGS $(DDSUBLINK abi, ModuleInfo, $(TT ModuleInfo)) is supported. Evaluates to false when compiling with command line switch $(DDSUBLINK dmd, switch-betterC, $(TT -betterC)))) $(TROW $(ARGS $(D D_TypeInfo)) , $(ARGS Runtime type information (a.k.a TypeInfo) is supported. Evaluates to false when compiling with command line switch $(DDSUBLINK dmd, switch-betterC, $(TT -betterC)))) $(TROW $(ARGS $(D D_Coverage)) , $(ARGS $(DDLINK articles/code_coverage, Code coverage analysis, Code coverage analysis) instrumentation (command line switch $(DDSUBLINK dmd, switch-cov, $(TT -cov))) is being generated)) $(TROW $(ARGS $(D D_Ddoc)) , $(ARGS $(DDLINK spec/ddoc, Embedded Documentation, Ddoc) documentation (command line switch $(DDSUBLINK dmd, switch-D, $(TT -D))) is being generated)) $(TROW $(ARGS $(D D_InlineAsm_X86)) , $(ARGS $(DDLINK spec/iasm, Inline Assembler, Inline assembler) for X86 is implemented)) $(TROW $(ARGS $(D D_InlineAsm_X86_64)) , $(ARGS $(DDLINK spec/iasm, Inline Assembler, Inline assembler) for X86-64 is implemented)) $(TROW $(ARGS $(D D_LP64)) , $(ARGS $(B Pointers) are 64 bits (command line switch $(DDSUBLINK dmd, switch-m64, $(TT -m64))). (Do not confuse this with C's LP64 model))) $(TROW $(ARGS $(D D_X32)) , $(ARGS Pointers are 32 bits, but words are still 64 bits (x32 ABI) (This can be defined in parallel to $(D X86_64)))) $(TROW $(ARGS $(D D_HardFloat)) , $(ARGS The target hardware has a floating-point unit)) $(TROW $(ARGS $(D D_SoftFloat)) , $(ARGS The target hardware does not have a floating-point unit)) $(TROW $(ARGS $(D D_PIC)) , $(ARGS Position Independent Code (command line switch $(DDSUBLINK dmd-linux, switch-fPIC, $(TT -fPIC))) is being generated)) $(TROW $(ARGS $(D D_PIE)) , $(ARGS Position Independent Executable (command line switch $(DDSUBLINK dmd-linux, switch-fPIE, $(TT -fPIE))) is being generated)) $(TROW $(ARGS $(D D_SIMD)) , $(ARGS $(DDLINK spec/simd, simd, Vector extensions) (via $(D __simd)) are supported)) $(TROW $(ARGS $(D D_AVX)) , $(ARGS AVX Vector instructions are supported)) $(TROW $(ARGS $(D D_AVX2)) , $(ARGS AVX2 Vector instructions are supported)) $(TROW $(ARGS $(D D_Version2)) , $(ARGS This is a D version 2 compiler)) $(TROW $(ARGS $(D D_NoBoundsChecks)) , $(ARGS Array bounds checks are disabled (command line switch $(DDSUBLINK dmd, switch-boundscheck, $(TT -boundscheck=off))))) $(TROW $(ARGS $(D D_ObjectiveC)) , $(ARGS The target supports interfacing with Objective-C)) $(TROW $(ARGS $(D D_ProfileGC)) , $(ARGS GC allocations being profiled (command line switch $(DDSUBLINK dmd, switch-profile, $(TT -profile=gc))))) $(TROW $(ARGS $(D D_Optimized)) , $(ARGS Compiling with enabled optimizations (command line switch $(DDSUBLINK dmd, switch-O, $(TT -O))))) $(TROW $(ARGS $(D Core)) , $(ARGS Defined when building the standard runtime)) $(TROW $(ARGS $(D Std)) , $(ARGS Defined when building the standard library)) $(TROW $(ARGS $(D unittest)) , $(ARGS $(DDLINK spec/unittest, Unit Tests, Unit tests) are enabled (command line switch $(DDSUBLINK dmd, switch-unittest, $(TT -unittest))))) $(TROW $(ARGS $(D assert)) , $(ARGS Checks are being emitted for $(GLINK2 expression, AssertExpression)s)) $(TROW $(ARGS $(D D_PreConditions)) , $(ARGS Checks are being emitted for $(DDSUBLINK spec/function, contracts, in contracts))) $(TROW $(ARGS $(D D_PostConditions)) , $(ARGS Checks are being emitted for $(DDSUBLINK spec/function, contracts, out contracts))) $(TROW $(ARGS $(D D_Invariants)) , $(ARGS Checks are being emitted for $(DDSUBLINK spec/class, invariants, class invariants) and $(DDSUBLINK spec/struct, Invariant, struct invariants))) $(TROW $(ARGS $(D none)) , $(ARGS Never defined; used to just disable a section of code)) $(TROW $(ARGS $(D all)) , $(ARGS Always defined; used as the opposite of $(D none))) ) $(DDOC_BLANKLINE ) $(P The following identifiers are defined, but are deprecated: ) $(DDOC_BLANKLINE ) $(TABLE2 Predefined Version Identifiers (deprecated), Version Identifier, Description $(TROW $(D darwin), The Darwin operating system; use $(D OSX) instead) $(TROW $(D Thumb), ARM in Thumb mode; use $(D ARM_Thumb) instead) $(TROW $(D S390X), The System/390X architecture, 64-bit; use $(D SystemZ) instead) ) $(DDOC_BLANKLINE ) $(P Others will be added as they make sense and new implementations appear. ) $(DDOC_BLANKLINE ) $(P To allow for future growth of the language, the version identifier namespace beginning with "D$(UNDERSCORE )" is reserved for identifiers indicating D language specification or new feature conformance. Further, all identifiers derived from the ones listed above by appending any character(s) are reserved. This means that e.g. $(D ARM_foo) and $(D Windows_bar) are reserved while $(D foo_ARM) and $(D bar_Windows) are not. ) $(DDOC_BLANKLINE ) $(P Furthermore, predefined version identifiers from this list cannot be set from the command line or from version statements. (This prevents things like both $(D Windows) and $(D linux) being simultaneously set.) ) $(DDOC_BLANKLINE ) $(P Compiler vendor specific versions can be predefined if the trademarked vendor identifier prefixes it, as in: ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD version)(DigitalMars_funky_extension) { ... } ) $(DDOC_BLANKLINE ) $(P It is important to use the right version identifier for the right purpose. For example, use the vendor identifier when using a vendor specific feature. Use the operating system identifier when using an operating system specific feature, etc. ) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LNAME2 debug, Debug Condition)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME DebugCondition): $(D debug) $(D debug $(LPAREN)) $(GLINK_LEX Identifier) $(D $(RPAREN )) ) $(DDOC_BLANKLINE ) $(P Two versions of programs are commonly built, a release build and a debug build. The debug build includes extra error checking code, test harnesses, pretty-printing code, etc. The debug statement conditionally compiles in its statement body. It is D's way of what in C is done with $(CODE #ifdef DEBUG) / $(CODE #endif) pairs. ) $(DDOC_BLANKLINE ) $(P The $(D debug) condition is satisfied when the $(D -debug) switch is passed to the compiler. ) $(DDOC_BLANKLINE ) $(P The $(D debug $(LPAREN)) $(I Identifier) $(D $(RPAREN )) condition is satisfied when the debug identifier matches $(I Identifier). ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD class) Foo { $(D_KEYWORD int) a, b; $(D_KEYWORD debug): $(D_KEYWORD int) flag; } ) $(DDOC_BLANKLINE )

$(LNAME2 DebugStatement, Debug Statement)

$(DDOC_BLANKLINE ) $(P A $(GLINK ConditionalStatement) that has a $(GLINK DebugCondition) is called a $(I DebugStatement). $(I DebugStatements) have relaxed semantic checks in that pure, @nogc, nothrow and @safe checks are not done. Neither do $(I DebugStatements) influence the inference of pure, @nogc, nothrow and @safe attributes.) $(DDOC_BLANKLINE ) $(UNDEFINED_BEHAVIOR Since these checks are bypassed, it is up to the programmer to ensure the code is correct. For example, throwing an exception in a nothrow function is undefined behavior. ) $(DDOC_BLANKLINE ) $(BEST_PRACTICE This enables the easy insertion of code to provide debugging help, by bypassing the otherwise stringent attribute checks. Never ship release code that has $(I DebugStatements) enabled. ) $(DDOC_BLANKLINE )

$(LNAME2 debug_specification, Debug Specification)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME DebugSpecification): $(D debug =) $(GLINK_LEX Identifier) $(D ;) ) $(DDOC_BLANKLINE ) $(P Debug identifiers are set either by the command line switch $(D -debug) or by a $(I DebugSpecification). ) $(DDOC_BLANKLINE ) $(P Debug specifications only affect the module they appear in, they do not affect any imported modules. Debug identifiers are in their own namespace, independent from version identifiers and other symbols. ) $(DDOC_BLANKLINE ) $(P It is illegal to forward reference a debug specification: ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD debug)(foo) writeln($(D_STRING "Foo")); $(D_KEYWORD debug) = foo; $(D_COMMENT // error, foo used before set )) $(DDOC_BLANKLINE ) $(P $(I DebugSpecification)s may only appear at module scope.) $(DDOC_BLANKLINE ) $(P Various different debug builds can be built with a parameter to debug: ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD debug)(identifier) { } $(D_COMMENT // add in debug code if debug keyword is identifier )) $(DDOC_BLANKLINE ) $(P These are presumably set by the command line as and $(D -debug=)$(I identifier). ) $(DDOC_BLANKLINE )

$(LNAME2 staticif, Static If Condition)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME StaticIfCondition): $(D static if $(LPAREN)) $(ASSIGNEXPRESSION ) $(D $(RPAREN )) ) $(DDOC_BLANKLINE ) $(P $(ASSIGNEXPRESSION ) is implicitly converted to a boolean type, and is evaluated at compile time. The condition is satisfied if it evaluates to $(D true). It is not satisfied if it evaluates to $(D false). ) $(DDOC_BLANKLINE ) $(P It is an error if $(ASSIGNEXPRESSION ) cannot be implicitly converted to a boolean type or if it cannot be evaluated at compile time. ) $(DDOC_BLANKLINE ) $(P $(I StaticIfCondition)s can appear in module, class, template, struct, union, or function scope. In function scope, the symbols referred to in the $(ASSIGNEXPRESSION ) can be any that can normally be referenced by an expression at that point. ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD const) $(D_KEYWORD int) i = 3; $(D_KEYWORD int) j = 4; $(CODE_HIGHLIGHT $(D_KEYWORD static) $(D_KEYWORD if)) (i == 3) $(D_COMMENT // ok, at module scope ) $(D_KEYWORD int) x; $(D_KEYWORD class) C { $(D_KEYWORD const) $(D_KEYWORD int) k = 5; $(CODE_HIGHLIGHT $(D_KEYWORD static) $(D_KEYWORD if)) (i == 3) $(D_COMMENT // ok ) $(D_KEYWORD int) x; $(ARGS $(D_KEYWORD else)) $(D_KEYWORD long) x; $(CODE_HIGHLIGHT $(D_KEYWORD static) $(D_KEYWORD if)) (j == 3) $(D_COMMENT // error, j is not a constant ) $(D_KEYWORD int) y; $(CODE_HIGHLIGHT $(D_KEYWORD static) $(D_KEYWORD if)) (k == 5) $(D_COMMENT // ok, k is in current scope ) $(D_KEYWORD int) z; } ) $(SPEC_RUNNABLE_EXAMPLE_FAIL $(D_CODE $(D_KEYWORD template) Int($(D_KEYWORD int) i) { $(ARGS $(D_KEYWORD static) $(D_KEYWORD if)) (i == 32) $(D_KEYWORD alias) Int = $(D_KEYWORD int); $(ARGS $(D_KEYWORD else) $(D_KEYWORD static) $(D_KEYWORD if)) (i == 16) $(D_KEYWORD alias) Int = $(D_KEYWORD short); $(ARGS $(D_KEYWORD else)) $(D_KEYWORD static) $(D_KEYWORD assert)(0); $(D_COMMENT // not supported )} Int!(32) a; $(D_COMMENT // a is an int )Int!(16) b; $(D_COMMENT // b is a short )Int!(17) c; $(D_COMMENT // error, static assert trips )) ) $(DDOC_BLANKLINE ) $(P A $(I StaticIfCondition) differs from an $(I IfStatement) in the following ways: ) $(DDOC_BLANKLINE ) $(OL $(LI It can be used to conditionally compile declarations, not just statements. ) $(LI It does not introduce a new scope even if $(D { }) are used for conditionally compiled statements. ) $(LI For unsatisfied conditions, the conditionally compiled code need only be syntactically correct. It does not have to be semantically correct. ) $(LI It must be evaluatable at compile time. ) ) $(DDOC_BLANKLINE )

$(LNAME2 staticforeach, Static Foreach)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME StaticForeach): $(D static) $(GLINK2 statement, AggregateForeach) $(D static) $(GLINK2 statement, RangeForeach) $(DDOC_BLANKLINE ) $(GNAME StaticForeachDeclaration): $(GLINK StaticForeach) $(GLINK2 attribute, DeclarationBlock) $(GLINK StaticForeach) $(D :) $(GLINK2 module, DeclDefs)$(OPT ) $(DDOC_BLANKLINE ) $(GNAME StaticForeachStatement): $(GLINK StaticForeach) $(GLINK2 statement, NoScopeNonEmptyStatement) ) $(DDOC_BLANKLINE ) $(P The aggregate/range bounds are evaluated at compile time and turned into a sequence of compile-time entities by evaluating corresponding code with a $(GLINK2 statement, ForeachStatement)/$(GLINK2 statement, ForeachRangeStatement) at compile time. The body of the $(D static foreach) is then copied a number of times that corresponds to the number of elements of the sequence. Within the i-th copy, the name of the $(D static foreach) variable is bound to the i-th entry of the sequence, either as an $(D enum) variable declaration (for constants) or an $(D alias) declaration (for symbols). (In particular, $(D static foreach) variables are never runtime variables.) ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD static) $(D_KEYWORD foreach)(i; [0, 1, 2, 3]) { $(D_KEYWORD pragma)(msg, i); } ) ) $(DDOC_BLANKLINE ) $(P $(D static foreach) supports multiple variables in cases where the corresponding $(D foreach) statement supports them. (In this case, $(D static foreach) generates a compile-time sequence of tuples, and the tuples are subsequently unpacked during iteration). ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD static) $(D_KEYWORD foreach)(i, v; ['a', 'b', 'c', 'd']) { $(D_KEYWORD static) $(D_KEYWORD assert)(i + 'a' == v); } ) $(DDOC_BLANKLINE ) $(P Like bodies of $(GLINK ConditionalDeclaration)s, a $(D static foreach) body does not introduce a new scope. Therefore, it can be used to generate declarations: ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD import) std.range : iota; $(D_KEYWORD static) $(D_KEYWORD foreach)(i; iota(0, 3)) { $(D_KEYWORD mixin)($(D_STRING `enum x`), i, $(D_STRING ` = i;`)); } $(D_KEYWORD pragma)(msg, x0, $(D_STRING " "), x1,$(D_STRING " "), x2); $(D_COMMENT // 0 1 2 )) ) $(DDOC_BLANKLINE ) $(P Inside a function, if a new scope is desired for each expansion, use another set of braces:) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD void) fun() { $(D_KEYWORD static) $(D_KEYWORD foreach)(s; [$(D_STRING "hi"), $(D_STRING "hey"), $(D_STRING "hello")]) {{ $(D_KEYWORD enum) len = s.length; $(D_COMMENT // local to each iteration ) $(D_KEYWORD static) $(D_KEYWORD assert)(len <= 5); }} $(D_KEYWORD static) $(D_KEYWORD assert)(!$(D_KEYWORD is)($(D_KEYWORD typeof)(len))); } ) ) $(DDOC_BLANKLINE )

$(LNAME2 break-continue, break and continue)

$(DDOC_BLANKLINE ) $(P As $(D static foreach) is a code generation construct and not a loop, $(D break) and $(D continue) cannot be used to change control flow within it. Instead of breaking or continuing a suitable enclosing statement, such an usage yields an error (this is to prevent misunderstandings). ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD int) test($(D_KEYWORD int) x) { $(D_KEYWORD int) r = -1; $(D_KEYWORD switch)(x) { $(D_KEYWORD static) $(D_KEYWORD foreach)(i; 0 .. 100) { $(D_KEYWORD case) i: r = i; $(D_KEYWORD break); $(D_COMMENT // error ) } $(D_KEYWORD default): $(D_KEYWORD break); } $(D_KEYWORD return) r; } $(D_KEYWORD static) $(D_KEYWORD foreach)(i; 0 .. 200) { $(D_KEYWORD static) $(D_KEYWORD assert)(test(i) == (i < 100 ? i : -1)); } ) $(DDOC_BLANKLINE ) $(P An explicit $(D break)/$(D continue) label can be used to avoid this limitation. (Note that $(D static foreach) itself cannot be broken nor continued even if it is explicitly labeled.) ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD int) test($(D_KEYWORD int) x) { $(D_KEYWORD int) r = -1; Lswitch: $(D_KEYWORD switch)(x) { $(D_KEYWORD static) $(D_KEYWORD foreach)(i; 0 .. 100) { $(D_KEYWORD case) i: r = i; $(D_KEYWORD break) Lswitch; } $(D_KEYWORD default): $(D_KEYWORD break); } $(D_KEYWORD return) r; } $(D_KEYWORD static) $(D_KEYWORD foreach)(i; 0 .. 200) { $(D_KEYWORD static) $(D_KEYWORD assert)(test(i) == (i<100 ? i : -1)); } ) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LEGACY_LNAME2 StaticAssert, static-assert, Static Assert)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME StaticAssert): $(D static assert $(LPAREN)) $(GLINK2 expression, ArgumentList) $(D $(RPAREN ) ;) ) $(DDOC_BLANKLINE ) $(P The first $(ASSIGNEXPRESSION ) is evaluated at compile time, and converted to a boolean value. If the value is true, the static assert is ignored. If the value is false, an error diagnostic is issued and the compile fails. ) $(DDOC_BLANKLINE ) $(P On failure, any subsequent $(I AssignExpression)s will each be converted to string and then concatenated. The resulting string will be printed out along with the error diagnostic. ) $(DDOC_BLANKLINE ) $(P Unlike $(GLINK2 expression, AssertExpression)s, $(I StaticAssert)s are always checked and evaluated by the compiler unless they appear in an unsatisfied conditional. ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD void) foo() { $(D_KEYWORD if) (0) { $(D_KEYWORD assert)(0); $(D_COMMENT // never trips ) $(D_KEYWORD static) $(D_KEYWORD assert)(0); $(D_COMMENT // always trips ) } $(D_KEYWORD version) (BAR) { } $(D_KEYWORD else) { $(D_KEYWORD static) $(D_KEYWORD assert)(0); $(D_COMMENT // trips when version BAR is not defined ) } } ) $(DDOC_BLANKLINE ) $(P $(I StaticAssert) is useful tool for drawing attention to conditional configurations not supported in the code. ) $(DDOC_BLANKLINE ) $(SPEC_SUBNAV_PREV_NEXT contracts, Contract Programming, traits, Traits) ) )