Instead of being a radical departure from current traditions in the evolution of programming languages, we strongly believe that reflective languages are in fact the ultimate result of a long and natural evolution. We concur with Halpern that the pursuit of ever late binding time had a great impact on the history of software development in general but also of programming languages in particular. The underlying principle is that all options should be kept open until the last possible moment.
This restrictive definition has the advantage of being very clear. An example of a binding is the one of a variable name to a memory location, which happens at program design time in machine language (and in early programming languages) but has been postponed to compile time or run-time in modern programming languages. Another example is the binding in a procedure call of the procedure name to the address of the code to be run. In procedural languages, this binding is done at compile time while in object-oriented languages it is postponed to the run-time.
In practice, the notion of binding times has evolved towards a much more general one. We now speak about binding a program element to a particular property as the choice of the property among a set of possible properties. The class of binding times includes the design, specification or implementation of the programming language, or the design, specification, implementation, translation or running of the program. Furthermore, we distinguish formal binding times from actual ones.
For example, we have just mentioned the late-binding of procedure names to the address of the code in object-oriented languages. This is a formal binding time. In a particular case, a static analysis of the program code may allow the compiler to bind a particular method call in a program to a specific code address. This is the actual binding time of this particular method call.
The notion of binding time is crucial to understand, compare and contrast the design and implementation of programming languages. Later binding times introduce more flexibility, at the expense of transferring the costs of the bindings towards later stages of processing. The general trend in the evolution of programming languages has been to postpone formal binding times towards the running of programs, but to use more and more sophisticated analyses and implementation techniques to bring actual binding times back to the earlier stages, where the costs of bindings are less harmful. Recently, control-flow analyses have been successfully implemented in Scheme compilers to determine the set of possible lambdas that can be applied at each call site. Likewise, concrete type analyses have been used in compilers for object-oriented languages to determine the set of possible instantiation classes of the receiving object at each method call site, in order to perform the lookup for the actual method at compile time.
Reflective programming languages pursue this tradition of ever late binding times by postponing the binding of almost all elements of programs and languages to the run-time. In this sense, we can speak of an outcome of this long tradition where everything is subject to modification until, and even during run-time. This is clearly the challenge in the efficient implementation of reflective languages. However, in the rest of this paper, we will claim that if formal binding times are postponed to run-time, the research should focus on new tools and implementation techniques aiming at bringing the actual binding times back to compile time. The challenge is still formidable, but the road ahead reveals itself much more clearly.