Compile Time Evaluation
During compilation, constant expressions will automatically be folded. Together with the compile
time conditional statements $if
, $switch
and the compile time iteration statements $for
$foreach
it is possible to perform limited compile time execution.
Compile time values
During compilation, global constants are considered compile time values, as are any derived constant values, such as type names and sizes, variable alignments etc.
Inside of a macro or a function, it is possible to define mutable compile time variables. Such
local variables are prefixed with $
(e.g. $foo
). It is also possible to define local type variables,
that are also prefixed using $
(e.g. $MyType
$ParamType
).
Mutable compile time variables are not allowed in the global scope.
$if and $switch
$if <const expr>:
takes a compile time constant value and evaluates it to true or false.
For switching between multiple possibilities, use $switch
.
Switching without argument is also allowed, which works like an if-else chain:
Loops using $foreach and $for
$for
… $endfor
works analogous to for
, only it is limited to using compile time variables. $foreach
… $endforeach
similarly
matches the behaviour of foreach
.
Compile time looping:
Looping over enums:
An important thing to note is that the content of the $foreach
or $for
body must be at least a complete statement.
It’s not possible to compile partial statements.
Compile time macro execution
If a macro only takes compile time parameters, that is only $
-prefixed parameters, and then does not generate
any other statements than returns, then the macro will be completely compile time executed.
This constant evaluation allows us to write some limited compile time code. For example, this macro will compute Fibonacci at compile time:
It is important to remember that if we had replaced $n
with n
the compiler would have complained. n <= 1
is not be considered to be a constant expression, even if the actual argument to the macro was a constant.
This limitation is deliberate, to offer control over what is compiled out and what isn’t.
Conditional compilation at the top level using @if
At the top level, conditional compilation is controlled using with @if
attributes on declarations
The argument to @if
must be possible to resolve to a constant at compile time. This means that argument
may also be a compile time evaluated macro:
Evaluation order of top level conditional compilation
Conditional compilation at the top level can cause unexpected ordering issues, especially when combined with
$defined
. At a high level, there are three phases of evaluation:
- Non-conditional declarations are registered.
- Conditional module sections are either discarded or have all of their non-conditional declarations registered.
- Each module in turn will evaluate
@if
attributes for each module section.
The order of module and module section evaluation in (2) and (3) is not deterministic and any use of $defined
should not
rely on this ordering.
Compile time introspection
At compile time, full type information is available. This allows for creation of reusable, code generating, macros for things like serialization.
To read more about all the fields available at compile time, see the page on reflection.
Compile time functions
A set of compile time functions are available at compile time:
$alignof
Get the alignment of something. See reflection.
$append
Append a compile time constant to a compile time array or untyped list.
$assert
Check a condition at compile time.
$assignable
Check if an expression is assignable to the given type, e.g. Type x = expr;
would be valid.
$defined
Returns true if a type or identifier is defined. See reflection.
$echo
Print a message to stdout when compiling the code.
$embed
Embed binary data from a file. See expressions.
$error
When this is compiled, issue a compile time error.
$eval
Converts a compile time string to the corresponding variable or function. See reflection.
$evaltype
Converts a compile time string to the corresponding type. See reflection.
$exec
Execute a script at compile time and include the result in the source code.
$extnameof
, $qnameof
and $nameof
Get the external name of a symbol. See reflection.
$feature
Check if a given feature is enabled.
$is_const
Check if the expression is constant at compile time.
$nameof
Get the local name of a symbol. See reflection.
$offsetof
Get the offset of a member. See reflection.
$qnameof
Get the qualified name of a symbol. See reflection.
$vacount
Return the number of macro vaarg arguments
$vaconst
Return a vaarg as a $constant
parameter.
$vaexpr
Return a vaarg as an #expr
parameter.
$varef
Return a vaarg as a &ref
parameter.
$vasplat
Expand the vaargs in an initializer list or function call.
$vatype
Get a vaarg as a $Type
parameter.
$sizeof
Return the size of an expression.
$stringify
Turn an expression into a string.
$typeof
Get the type of an expression (without evaluating it).
$typefrom
Get a type from a compile time constant typeid
.