s taken during compilation
of a program (principally as opposed to actions taken at run time
) are compile time actions
. Compile time occurs essentially once
for any program
; run time recurs whenever the program is run.
Some programming languages have various facilities for specifying compile time actions. These include macro facilities like in Common Lisp and C (and C++)1, the template facilities of C++, and IMMEDIATE words in Forth.
Other actions may take place at compile time even without explicit programmer specification; generally these are optimizations automatically applied by the compiler (e.g. loop unrolling and constant folding). Unfortunately, the programmer's decision to leave such constructs for automatic compile time expansion involves knowing that the compiler will indeed perform the expansion; depending on the compile time behaviour thus requires the use of a construct guaranteed to be expanded, and is therefore every bit as bad as explicitly requesting the compile time behaviour.
Languages like Lisps and Forth offer the use of all language facilities at compile time. This is very useful, but must be used sparingly and cautiously to avoid creating an unmaintainable mess. In particular, the formal problem of syntax checking a program in such a language (i.e. asking if it compiles) becomes undecidable (not recursive)!
C++ templates use an entirely different syntax than C++ "run time" code. Amazingly, these templates turn out to provide a Turing complete computing facility in their own right! (See C++: computing Fibonacci numbers at compile time for an example of the misuse of this facility). This capability, apparently inadvertently provided by the language designers, makes the formal problem of syntax checking a C++ program also undecidable.2 blitz++ is a numerical library which uses this facility to create efficient codes for a given problem size at compile time.
- Macro expansion is sometimes considered a "precompilation phase", especially in the C and C++ worlds. Such a distinction is not particularly useful here, in the face of macro facilities such as those available in Lisp.
- In fact, an entry in the IOCCC showed that even the C preprocessor's #include, #define and #if facilities are sufficient to introduce Turing completeness into the compile time language!