Dynamic Lisp

Summary: Dynamic languages can be changed while the program is running, which makes applications easier to develop and maintain. This is orthogonal to issues of compilation vs. interpretation, development environments, and static vs dynamic typing.
prev next

site map



To say that a language is dynamic may mean different things:

  • That the language is exciting to work with.
  • That the types of data can be examined and checked at run-time.
  • That the behavior of functions and other operations can be changed (or created) at run-time.
Here we mean the last of these. In particular, the behavior of a Lisp program can be modified while the program is running without necessarilly having access to the original source code, and in any case without having access to or knowledge of those parts of the application which are uneffected by the change. The changes to the program may be made interactively by a programmer or by the program itself.

There are several ways in which this comes about:

  1. Function are first-class. A "function factory" can be constructed which returns function objects as values. If the "function factory" is compiled, these function objects are compiled, too. These programs can then be explicitly called on arguments. Thus a program can produce the functions it needs at run time, making different functions for different situations.

  2. The global definition of a named function can be changed at run-time, simply by creating one of these function objects and storing it in the symbol that represents the name of the function.

    By default, the compiler must arrange for callers of a global function to access the object stored in the symbol naming the function. There are various optimizations permitted where this is not done, however. Some implementations provide for both the direct call optimizations and the redefinition of global functions.

  3. The function LOAD can be called by any Lisp program. If the file being loaded contains new definitions, these are added and made available to the application that called LOAD. If the file being loaded contains new definitions of existing functions, classes, etc., these definitions replace the existing definitions in the manner described above. The Common Lisp Object System allows classes to be redefined in running programs, and the system will automatically update existing instances of the changed class to conform to the new definition. The programmer has control over how this updating is performed. In addition, the function COMPILE-FILE can be called by any Lisp program, including one which just created the Lisp source file to be compiled. The result can then be loaded with LOAD.

  4. The function EVAL can be called by any Lisp program. This evaluates a list representation of a program. There are many Lisp utilities for examining and creating list data. These can be used to construct programs on-the-fly which are then evaluated. In addition, the function COMPILE can be called by any Lisp program to create compiled-functions directly from list data representations of programs. These techniques make it easy to write Computer Aided Software Engineering (CASE) and other software development systems in Common Lisp.
Using a dynamic language provides several benefits:

  • Programs can be developed and delivered more easily.

    • It is not necessary to define all parts of an application before testing or even delivering part of it. The combination of the Lisp top-level and the function LOAD do not use a traditional static program linker, so one can start the program running without having to track down all undefined references. If the missing parts are never used, there will never be a problem.

    • When there is a problem, only the broken part need be redefined. This can be done while the application is still running. There is no need to laboriously stop the application, recompile everything, restart the application, and recreate the error state before proceding with testing.

  • Mission-critical applications can be maintined more easily.

    • Bug fixes or new functionality can be installed without stopping the application.

    • Only the bug fix or new functionality need be distributed and loaded. For large applications distributed over modem or other networks, this can be a major consideration.

  • The programs themselves can be simpler, more robust and easier to develop and maintain. This comes partly from:

    • The ability to have functions create other first-class functions on the fly. See Object-Oriented and Procedural Lisp.

    • The fact that Lisp comes with the functions LOAD, READ and EVAL which make it easy for anyone to create initilization or customization files that set global variables, etc. There is no need for an application developer to write such functions, they are already there.

    • The well-defined, object-oriented way in which programmers can define how data reconforms itself to changed class definitions makes such code quite clean.

    • These features can be exposed, at the programmer's discretion, to general users of an application for the purpose of customization. There is no need to define and develop a "customization" or "user macro" language as Lisp itself has everything needed.

All of this is independent of the environment in which the application is to be run. For example, even in a Lisp implementation that supports the creation of stand-alone applications which run outside the Lisp top-level, that application can still be defined to provide the user with a command that calls the function LOAD (perhaps after first confirming a manager's password).

A key commonality to the above benefits is that the cost of making a change to a dynamic system is proportional to the size of the change, whereas the cost of making the same change in a static system is generally proportional to the size of the system. As the size of systems or the expected numbers of changes grow, it becomes increasingly important to support more aspects of the system dynamically.