Linguistic Reflection

From SystemsResearch

Jump to: navigation, search

Linguistic reflection, also called structural reflection, gives a programming system the ability to generate new program fragments and incorporate them into the ongoing computation. This has several applications in a persistent environment including supporting safe evolution of long-lived programs and data, and specifying highly generic programs that may be reused in many contexts. In strongly typed systems the linguistic reflection process includes checking of the generated program fragments to ensure type safety.

Forms of linguistic reflection are provided in Lisp, Scheme and POP-2. Research here, however, focuses on strongly typed languages, relevant examples of which include PS-algol, Napier88 and TRPL. Linguistic reflection in these languages involves the execution of generator procedures which produce as their results representations of program fragments in the corresponding language. These program fragments are incorporated into the application after the appropriate validity checks.

Two varieties of type-safe linguistic reflection can be identified; these vary as to the time at which generator execution takes place. With compile time linguistic reflection, supported in TRPL, the generators are evaluated during the course of program compilation and the new code produced is incorporated into the program being compiled. This technique could be viewed as a sophisticated form of macro expansion, where the language used to evaluate the macro is the same as the programming language itself. With run time linguistic reflection, supported in PS-algol and Napier88, the generators are evaluated during program execution and the new code produced is compiled and executed in the same context. Both forms of linguistic reflection have the effect of blurring the distinction between compile time and run time.

One application of linguistic reflection is in supporting evolution in strongly typed persistent systems. The inevitable changes to meta-data in long-lived systems give rise to the problem of consistently changing all the affected programs and data. Given some mechanism for locating the relevant programs and data, linguistic reflection can be used to introduce transformed versions in a controlled manner.

Another application is in providing highly generic programs. The reuse of existing software reduces development and maintenance costs; the more generic, or widely applicable, a software component is, the more likely it will be reused. Polymorphism is one powerful mechanism for genericity. There exist, however, some generic computations which are hard or impossible to express using parametric or inclusion polymorphism. The difficulty lies in the fact that the course of such a computation depends on details of the types of the input parameters, while parametric and inclusion polymorphism by their nature abstract such details away. A well used example is that of a strongly typed natural join function, where the algorithm and the type of the result relation depend on the types of the input relations. This can be implemented using linguistic reflection, by defining a generator procedure which accepts representations of the types of the relations to be joined and generates the representation of a procedure to perform the join for those types.

Thus linguistic reflection provides a rich form of ad-hoc polymorphism, with which generic yet type-dependent operators can be defined over wide ranges of types. This mechanism has some similarities with that of 4GL systems, where generic application descriptions are automatically tailored to specific instances. In this case the structure of the type system and the language defines the primitives over which the generators are written. It is somewhat ironic that the type system itself, which is often seen as restricting the expressibility of the language, can be used as the basis of very flexible and high level generation mechanisms. The technique is particularly suited to persistent systems since the persistent environment may be used as a cache to store executable versions of generated procedures. This means that the generator need not be executed more than once for given parameters.

One aspect of research involves refinement of the theory characterising the nature of linguistic reflection and its relation to other varieties such as behavioural reflection. Others are the investigation of static checking of generator programs, particularly in combination with hyper-programming techniques, and the development of tools to support the construction and maintainance of generators.

Further Information

Personal tools