Configuration Script

A Scripting Pattern

Problem

How can a system be split into reusable components without the overhead of evaluating Glue Code?

Context

The use of Glue Code involves memory and performance overhead for each component-to-component interaction. When performance is paramount or memory is limited, these overheads can be too great. Applications which must rapidly react to events, such as applications with graphical user interfaces, or those which must pass large amounts of data between components written in a systems programming language can find that Glue Code is inefficient.

Forces

  1. Components must be loosely coupled: they must rely on as few other components as possible.
  2. Components must be reusable: it must be possible to use them in as many situations involving as many other types of component as possible.
  3. Components cannot afford the overhead of evaluating a script for each interaction with another component.

Solution

Consequences

Components interact directly via binary interfaces. Direct component interactions are faster and require less memory than component interactions via Glue Code.

Components can share data structures and interact in ways not visible at the scripting level.

Components designed to be configured by scripts are are not as loosely coupled or reusable as those designed to interact via glue code. Programmers must carefully design the potential interactions between components and the roles they take in those interactions. In C++, these roles and interactions can be defined in terms of abstract interfaces. In C they can be defined in terms of function pointers and callbacks.

Because components interact directly, the script interpreter will not be able catch any errors. Any bugs will probably crash the application. Careful type-checking is required to ensure that components are given valid pointers. Associative containers can be used to map between opaque handles that are manipulated by scripts and pointers of a known type.

The Glue Code idiom provides greater flexibility and more potential for component reuse and is therefore often preferable if the performance and memory overheads can be tolerated.

It is important to note that a component implementor does not have to choose exclusively between Glue Code and Configuration Scripts. Components often support both forms of scripting, using glue code for some interactions and binary interfaces for others. For example, Tk's button widget uses glue code to specify what happens when the user pushes the button and a binary interface to make requests to its geometry manager.

Known Uses

This idiom is used to attach geometry managers to Tk widgets. Tk maintains a hash table which maps widget names to Tk_Window handles. The window structure referenced by a handle is used to store pointers to C functions which are called by the widget's implementation when it wants to interact with its geometry manager.

My own graph widget uses this idiom to connect nodes and arcs into a graph structure. Because graph layout algorithms are computationaly intensive, the algorithms are written in C++ and cannot afford the indirection of evaluating Tcl scripts to traverse the graph data structure.

Configuration Scripts are closely related to the use of specialised "Architecture Description Languages" such as Darwin. Indeed, one backend for the Darwin compiler generated Tcl scripts that connected the binary interfaces of distributed objects.


Nat Pryce (np2@doc.ic.ac.uk)