Because behavioral reflection implies the possibility of modifying the language semantics at run-time, most of the implementations tend to rely on interpretive techniques, which are easier to implement and by design more reactive to modifications. However, compiling is mandatory to get efficient languages and therefore make reflection of real interest. In this tutorial, we have proposed a new comprehensive approach to the efficient implementation of behavioral reflection based on the notion of binding times. We have introduced the distinction between static and dynamic behavioral reflection. We have argued that the static approach, while not covering all possible applications of behavioral reflection, is very powerful. It enables the compilation of reflective programs, sometimes using the available compiler techniques for modern dynamic languages.
In a more general setting, part of behavioral reflection is captured by the capability of extending the language's standard compiler. Compilers can either be constructed by hand or generated from some specification of the language syntax and semantics. Modifications can then be made either directly in the code of the compiler or by altering the specification and automatically generating a new compiler. In the field of compiler generation, the kind of specifications that have been used ranges from formal semantics (denotational, action or modular monadic semantics) to interpreters, either meta-circular or written in a low-level (assembly) language. The compiler itself can also be viewed as a low-level specification of the language semantics.
Unfortunately, a tension exists between high-level specifications, that eases the modifications, and the implementation, which needs a low-level (assembler) model to be run efficiently. The two can hardly coincide because low-level models are too detailed and tend not to be modular in terms of modifications. A modification made in low-level specification terms tends to spread all over the specification because of the coupling generally observed in these models. Open compilers tend to exhibit this kind of problem, but an interesting approach is to help the user in making modifications by providing default decisions, like in the Scheme open compiler of Lamping et al. [LKRR92].
An alternative is to use high-level models oriented towards the user but to automatically propagate the modifications from the high-level specification to the low-level model. We have assessed this approach in the reflection perspective and we have argued that incremental generation of compilers, either from extensible interpreters or from modular monadic semantics, currently appears as the most promising avenues.
Finally, we hope that the new approach to behavioral reflection as well as the thoughts expressed in this tutorial will help clarify the issues raised by its efficient implementation and that they will provide new research avenues to be explored by the reflective language community in the near future.