We might want to compile some extension features if and only if another module is available at compile-time to gracefully degrade when a dependency isn't installed. The most straightforward solution is to use the version
statement, passing the appropriate identifier to the dmd
command line. Can we also do it without extra compiler options from the user?
Let's execute the following steps to determine whether a module is available:
if
statement.The code is as follows:
static if(__traits(compiles, { import test.foo; })) { import test.foo; /* safe to use */ } else { // module not available, work around }
This is an example of a common strategy to poke around D: conditional compilation. Instead of trying to find metadata, we can often simply try to compile a block of code to attempt the task we're interested in. If that compilation fails, assume the task cannot be done with the arguments we're given. Anything we can encapsulate in a small function can be tested with __traits(compiles)
.
Since imports can be local to a function, we can wrap it in an anonymous function (the { code }
syntax expands to void delegate() { code }
) and see if it compiles. Once it does, the compiler has already loaded the module, so we can immediately use it.
Generally, any time you might get a compilation error and do not wish for it to be fatal, you may wrap the code in static if(__traits(compiles))
to selectively enable or disable iffy features. However, be careful not to overuse this. It is easy to hide minor mistakes and completely disable the code that never actually compiles! Keep the conditional code as simple as possible and always run it normally when you change it. This ensures that it actually does work when it is supposed to.
The __traits
function is a built-in language construct for special communication with the compiler. It always takes an operation identifier as the first argument, for example: compiles
, isSame
, allMembers
, getMember
, and others that can be found in the documentation. Subsequent arguments are specific to the operation. The compiles
identifier takes only one argument; an expression that it attempts to compile.
The __traits
function returns values in the form of compile-time constants that can be tested in static if
, stored in enums
or aliases
, or used directly. In the generated code, they will be indistinguishable from data literals. When __traits
returns a list, it does it as a TemplateArgumentList
(sometimes also called a TypeTuple
, though it can hold more things other than types). These lists may be looped over with the foreach
loop at compile time to inspect individual elements with all compile-time tools.
__traits
at http://dlang.org/traits.html. It has a list of all the available operations, their arguments, and their return values.compiles
trait at http://dlang.org/traits.html#compiles.3.144.91.47