Example

Imagine that you have written some numerical function, for example a function employing the Newton method for computing the square root. Such a function may be defined as in slide newton.
  double newton( double arg ) { 
\fbox{newton}
double r=arg, x=1, eps=0.0001; while( fabs(r - x) > eps ) { r = x; x = r - (r * r - arg) / (2 * r); } return r; }

slide: The function {\em newton}

When you have written such a function, you may wish to have a graphical interface to allow you to experiment with possible inputs in a flexible way. For example, you may wish to have a slider for setting the input value and a message widget displaying the outcome of the function. Such an interface may look like the one in slide tcl-interface. \fslide{tcl-interface}{ A graphical interface for newton }{ \hspace*{0.0cm}\epsfbox{interface.eps} } Admittedly, the newton function given above is simple enough to be implemented directly in Tcl. Nevertheless, since C++ is to be considered superior for implementing numerical functions, we decide to implement the Newton function in C++ and the graphical interface in Tcl. The problem we need to solve then is to connect the graphical interface with the C++ code.

The Tcl script

Let us start by defining the interface, where we will use a dummy function to generate the output. A Tcl script defining our interface is given in slide int-script. } \slide{int-script}{The definition of the interface}{
  #!/usr/prac/se/bin/hush -f
  
  proc generate {} { 
   	.m configure -text [.s get]
  }
  
  scale .s -label "seed" -orient horizontal -length 256 -relief sunken
  message .m -width 256 -aspect 200 
  
  pack .m .s -fill x
  
  bind .s  { generate }
  
} The script defines a slider, as a (horizontal) scale widget, and a message widget, that is used to display the output. The built-in Tcl/Tk bind function is used to associate the movement of the slider with the invocation of the Tcl function generate. Note that the function generate is a dummy function, which merely echos the the value of the scale widget to the message widget. Now we have developed a graphical interface, which may be tested by using the hush shell or wish. Next, we need to develop the C++ program embodying the numerical function and connect it to the interface written in Tcl. The structure of this program is best explained in four steps. Each of these steps corresponds with a code fragment. Together, these fragments form the C++ program of our example. We will first look at these steps. Afterwards it will be explained why the individual steps are needed.
  #include "hush.h"
  
  double newton(double arg);    
[1]
char* ftoa( double f);
to convert float to char*

slide: Step 1: Preliminaries

Step 1: The functional part is represented by the function newton. We need to declare its type to satisfy the compiler. The fragment displayed in slide step1, further shows the inclusion of the {\tt hush.h} header file and the declaration of an auxiliary function ftoa that is used to convert floating point values to a string. \slide{step2}{Step 2: The generator class}{ .ds lib/gen2.s .ds lib/genop.s } \c{ Step 2: The next step, shown in slide step2, involves the definition of the interfacing between the Tcl code and the C++ program. The class generator defines a so-called handler object that will be associated with the function generate employed in the script, overriding the dummy Tcl function generate as defined in the script. In order to access the scale and message widget defined for the interface, C++ pointers to these widgets are stored in instance variables of the object. These pointers are initialized when creating a generator object. The widgets are destroyed when deleting the object. Note that the widgets must first be destroyed before deleting the corresponding C++ objects. } \nop{ \slide{gen-op}{The generator action}{ .ds lib/genop.s } } \c{ All you need to know at this stage is that when the function generate is called in response to moving the slider, or more precisely releasing the mouse button, then the operator() function of the C++ generator object is called. In other words, the operator() function is (by convention) the function that is executed when a Tcl command that is bound to a handler object is called. The generator::operator() function, which is also displayed in slide step2, results in displaying the outcome of the newton function, applied to the value of the slider, in the message widget. } \slide{step3}{Step 3: The application class}{ .ds lib/gen3.s } \c{ Step 3: The third step, displayed in slide step3, is to define an application class, which is needed for the program to initialize the X-windows main event loop. An application class needs to be defined as a subclass of session. To initialize the program, the application class redefines the (virtual) function main inherited from the session class. The function application::main takes care of initializing the interface, creates an instance of the generator class (see slide step2), and binds the Tcl command generate (see slide int-script) to the generator object. } \slide{step4}{Step 4: The function main}{ .ds lib/gen4.s } \c{ Step 4: Finally, as displayed in slide step4, the function main is defined. A function main is required for each C or C++ program. It consists merely of creating an instance of the application class and the invocation of run, which starts the actual program. The example C++ program illustrates a number of features, some of which are typical for hush and some of which are due to programming in a window environment. In an ordinary C++ program the function main is used to start the computation. Control is effected by creating objects and calling the appropriate functions. When programming a window-based application, at a certain moment control is delegated to the window environment. Consequently, there needs to be some kind of main loop which waits for incoming events, in response to which the control may be delegated to an appropriate component of the program (slide step4). To hide the details of activating the main loop and the dispatching of events, the hush library provides a class session that allows you to define an application class to initialize your program (slide step3). In order to respond to events, the hush library provides a handler class, that allows you to associate a C++ object with a Tcl function. Each time the corresponding Tcl function is invoked, the operator() function of the object is called. The actual object is an instance of a derived class, redefining the virtual operator() function of the handler class (slide step2). Handler classes are typical for hush. Another feature typical for hush is the use of a kit object, that may be accessed by using the tk instance variable of the handler object. The kit object provides access to the Tcl interpreter embedded in the C++ program. In the example it is used to initialize the graphical interface by reading a script file and to define the association between the Tcl function generate and the C++ instance of generator. The widgets defined in the Tcl script are accessed in the C++ program by means of a scale and message pointer. The hush library provides for each Tk widget a class of the same name. Note that not the widgets themselves are created in the constructor of the generator class, but only abstract widget objects that are casted to the appropriate widget types. Casts are needed to access these objects as respectively a scale and message widget. Widgets can be created, however, directly in C++ as well, by employing the appropriate widget class constructors. See section user. As a final comment, the example illustrates a classical stratagem of software engineering, namely the separation of concerns. On the one hand we have a script defining the interface that may be independently tested, and on the other hand we have C++ code embodying the real functionality of our program. }