implementation details and carefully alter their implementation (either an interpreter
or a compiler), which is usually written in lower level languages. Reflective
languages allow such modifications within the same language framework using high
level abstractions without understanding low level implementation. Because of its
flexibility and extensibility, reflection is also important for practical purposes, i.e.,
as a basis for open implementation".
An important characteristic of reflective languages is their tower structure. In reflective languages, user programs at the baselevel (or level 0) are interpreted by the interpreter running at the level above (level 1, or metalevel ), which is in turn interpreted by the interpreter running at level 2, and so on. Conceptually, there is an infinite tower of interpreters. Reflective languages permit user programs to execute programs at any level in the tower, possibly accessing (introspecting) or modifying interpreters of upper levels.
However, the infinite tower structure makes it difficult to implement reflective languages. In conventional Lisp-based reflective languages, such as Brown and Blond, the tower is simulated by lazily creating interpreters which are directly executed by machine, instead of by interpretation at the level above. Although the use of directly executed interpreters is preferable for efficiency, it becomes impossible for user programs to alter (parts of) the interpreters selectively, since they are already in machine code form. For example, suppose we want to modify the metalevel interpreter so that it prints out all the expressions it evaluates. If the structure and implementation of the metalevel interpreter were available to user programs, we could achieve this just by inserting a print function at an appropriate place in the interpreter code. Such modifications are not possible in Brown and Blond since the interpreter is directly executed and available only as a single monolithic function called meaning.
Jefferson and Friedman, on the other hand, presented a Simple Reflective Interpreter IR, in which user programs are allowed to access and change the metalevel interpreters. Because in IR, the interpreter running at each level is implemented as ordinary user-defined functions, and actually interpreted by the interpreter one level above, we can freely redefine it to change its subsequent behavior. However, since IR is implemented by executing a metacircular interpreter on top of itself, it has two drawbacks: (1) it is extremely inefficient due to double (triple, etc.) interpretation, and (2) it requires the construction of an infinite tower if we want to achieve reflection at every level.
To be highly flexible and extensible, reflective languages should fulfill the following requirements:
1. User programs are allowed to access and change (parts of) metalevel interpreters.
2. Reflective facilities are available at every level.
3. The interpreter runs efficiently when reflection is not used, and reasonably well even if parts of it are modified.