Background -- Tcl/Tk

The language Tcl has first been presented in Ousterhout90. Tcl was announced as a flexible cshell-like language, intended to be used for developing an X11-based toolkit. A year later, the Tk toolkit (based on Tcl) was presented in Ousterhout91. From the start Tcl/Tk has received a lot of attention, since it provides a flexible and convenient way to develop rather powerful window applications. The Tcl language offers variables, assignment and a procedure construct. Also it provides a number of control constructs, facilities for manipulating strings and built-in primitives giving access to the underlying operating system. The basic Tcl language may easily be extended by associating a function written in C with a command name. Arguments given to the command are passed as strings to the function defining the command. The Tk toolkit is an extension of Tcl with commands to create and configure widgets for displaying text and graphics, and providing facilities for window management. The Tk toolkit, and the wish interpreter based on Tk, provides a convenient way to program X-window based applications.

Hello world


The wish program is an interpreter for executing Tcl/Tk scripts. As an example of a wish script, look at the hello world program below:
  button .b -text "hello world"  -command { puts "hello world" }
  pack .b 

This program results in the widget shown in figure Hello. It defines a button that displays hello world, and prints hello world to standard output when it is activated by pressing the left mouse button. The language used to write this script is simply Tcl with the commands defined by Tk, as for example the button command (needed to create a button) and the pack command (that is used to map the button to the screen). The wish program actually provides an example of a simple application based on Tcl/Tk. It may easily be extended to include for example 3D-graphics by linking the appropriate C libraries and defining the functions making this functionality available as (new) Tcl commands.

The Tcl C API

To define Tcl commands in C style, the programmer has to define a command function, with a profile similar to the function aCommand shown below, and declare the function to be a command in Tcl by invoking the Tcl_CreateCommand function:
  // Define a command function in C style
  int aCommand( ClientData data, Tcl_Interp* interp,
				 int args, char* argv[]) {

  some_type* x = (some_type*) data;        // conversion by cast
  // some processing

  // Declare the function aCommand as a Tcl command
  // for example in the  main  function
  some_type* user = new some_type(); // to create the client data
  Tcl_CreateCommand( interp, "aco", aCommand, (ClientData) user );

Creating a command is done with reference to an interpreter, which accounts for the first argument of Tcl_CreateCommand. The name of the command (aco in this case), as may be used in a Tcl script is given as a second argument, and the C style function defining the command as a third argument. Finally, the address of a structure containing client data (user in this case) is passed as the fourth parameter. When the function aCommand is invoked as the result of executing the Tcl command aco, the client data stored at declaration time is passed as the first argument to the function. Since the type ClientData is actually defined to be void*, the function must first cast the client data argument to an appropriate type as indicated above. Clearly, casting is error-prone. Another problem with command functions as used in the Tcl C API is that permanent data are possible only in the form of client data, global variables or static local variables. Both client data and global variables are unsafe by being too visible and static local data are simply inelegant. The hush library has been developed to offer a type-secure solution to the problem of connecting C++ code with Tcl, and to allow for a safe way of maintaining a (dynamically changing) state. In hush the preferred way is to employ handler objects. The obvious solution of associating class member functions with Tcl commands does not work since pointers to member functions are different from pointers to ordinary C style functions.