% % Tcl-93 Presentation of Stk % % Author: Erick Gallesio [eg@kaolin.unice.fr] % Creation date: 5-Apr-1993 12:29 % Last file update: 24-May-1993 22:12 \documentstyle[twocolumn,tcl]{article} \input{psfig} \begin{document} \bibliographystyle{unsrt} % % Commands % \newcommand{\stk}{{\sc STk }} \title{Embedding a Scheme Interpreter in the Tk Toolkit} {\footnotesize \author{ Erick Gallesio \\ Universit\'e de Nice~~-~~Sophia-Antipolis \\ Laboratoire I3S - CNRS URA 1376 - B\^at 4. \\ 250, avenue Albert Einstein \\ Sophia Antipolis \\ 06560 Valbonne - FRANCE}} \date{} \maketitle \vskip1cm \begin{abstract} {\it \stk is a graphical package which rely on Tk and the Scheme programming language. Concretely, it can be seen as the Tk package where the Tcl language as been {\em replaced} by a Scheme interpreter. Programming with {\stk} can be done at two distinct levels. First level is quite identical than programming Tk with Tcl. Second level of programming uses a full object oriented system. Those two programming levels and current implementation are described here.} \end{abstract} \section{Introduction} Today's available graphical toolkits for applicative languages are not satisfactory. Most of the time, they ask to the user to be an X expert which must cope with complicated arcane details such as server connections or queue events. This is a true problem, since people which use this kind of languages are generally not inclined in system programming and little of them get over the gap between the language and the toolkit abstraction levels. Tk is a powerful X11 graphical tool\-kit de\-fi\-ned at the University of Berkeley by J.Ousterhout \cite{Ouster-Tk}. This toolkit gives to the user high level widgets such as buttons or menu and is easily programmable. In particular, a little knowledge of X fundamentals are needed to build an application with it. Tk package rely on an interpretative language named Tcl \cite{Ouster-Tcl}. However, dependencies between those two packages are not too intricate and replacing Tcl by an applicative language was an exciting challenge. To keep intact the Tk/Tcl pair spirit, a little applicative language was necessary. Scheme \cite{SICP} was a good candidate to replace Tcl, because it is small, clean and well defined since it is an IEEE standard \cite{IEEE-Scheme}. Programming with {\stk} can be done at two distinct levels. First level is quite identical than programming Tk with Tcl, excepting several minor syntactic differences. Second level of programming uses a full object oriented system (with multi-inheritance, generic functions and a true meta object protocol). Those two levels of programming are briefly described in the two first sections. Section 4 is devoted to implementation and section 5 exposes some encountered problems when mixing Tk and Scheme. \section{\stk: First level} The first level of {\stk} uses the standard Scheme constructs. To work at this level, a user must know a little set of rewriting rules from the original Tk-Tcl library. With these rules, the Tk manual pages and a little knowledge of Scheme, he/she can easily build a {\stk} program. Creation of a new widget (button, label, canvas, ...) is done with special \stk primitives procedures. For instance, creating a new button can be done with \begin{verbatim} (button ".b") \end{verbatim} Note that the name of the widget must be ``stringified'' due to the Scheme evaluation mechanism. The call of a widget creation primitive defines a new Scheme object. This object, which is considered as a new basic type by the Scheme interpreter, is automatically stored in a variable whose name is equal to the string passed to the creation function. So, the preceding button creation would define an object stored in the~{\tt .b} variable. This object is a special kind of procedure which is generally used, as in pure Tk, to customize its associated widget. For instance, the expression {\small \begin{verbatim} (.b 'configure '-text "Hello, world" '-border 3) \end{verbatim} } \noindent permits to set the text and background options of the~{\tt .b} button. As we can see on this example, parameters must be well quoted in regard of the Scheme evaluation rules. Since this notation is barely crude, the Common Lisp keyword mechanism has been introduced in the Scheme interpreter {\cite{CLtl2}} {\footnote{A keyword is a symbol beginning with a colon. It can been seen as a symbolic constant (i.e. its value is itself)}}. Consequently, the preceding expression could have been written as \noindent {\small \begin{verbatim} (.b 'configure :text "Hello, world" :border 3) \end{verbatim} } \noindent which in turn is both close from Common Lisp and pure Tk. Of course, as in Tk, parameters can be passed at widget creation time and our button creation and initialization could have been done in a single expression: {\small \begin{verbatim} (button .b :text "Hello, world" :border 3) \end{verbatim} } The Tk binding mechanism, which serves to create widget event handlers follow the same kind of rules. The body of a Tk handler must be written, of course, in Scheme. Following example shows such a script; in this example, the label indicates how many times mouse button 3 has been depressed. Button press counter increment is achieved with the simple script given in the {\tt bind} call. {\small \begin{verbatim} (define count 0) (pack 'append "." (label ".l" :textvariable 'count) "fill") (bind .l "<3>" '(set! count (+ count 1))) \end{verbatim} } To illustrate {\stk} first level of programming, Figure~1 shows the simple file browser described in {\cite{Ouster-Tcl}} written in {\stk}. \begin{figure*}[t] {\small \vskip2mm \begin{quote} \begin{verbatim} #!/usr/local/bin/stk -f (scrollbar ".scroll" :command ".list 'yview") (listbox ".list" :yscroll ".scroll 'set" :relief 'raised :geometry "20x20") (pack 'append "." .scroll "right filly" .list "left expand fill") (define (browse dir file) (if (not (string=? dir ".")) (set! file (string-append dir "/" file))) (if (directory? file) (system (format #f "browse.stk ~A &" file)) (if (file? file) (let ((ed (getenv "EDITOR"))) (if ed (system (string-append ed " " file "&")) (system (string-append "xedit " file "&")))) (error "Bad directory or file" file)))) (define dir (if (> argc 0) (car argv) ".")) (system (format #f "ls -a ~A > /tmp/browse" dir)) (with-input-from-file "/tmp/browse" (lambda() (do ((f (read-line) (read-line))) ((eof-object? f)) (.list 'insert 'end f)))) (bind .list "" '(destroy ".")) (bind .list "" '(browse dir (selection 'get))) \end{verbatim} \end{quote} } \caption{\em A simple file browser} \vskip2mm \hrule \end{figure*} \section{\stk: Second level} Programming with material shown before is a little bit tedious and more complicated than coding with Tcl since one have to add parenthesis pairs and quote options values. Its only interest is to bring the power and flexibility of Tk to the Scheme world. The second level of \stk is far more interesting since it uses a full object oriented extension of the Scheme language. Defining an object oriented layer on Scheme is a current activity in the Scheme community and several packages are available. The object layer of \stk is derived from a package called {\em Tiny Clos}~{\cite{Tiny-Clos}}. This extension provides objects {\em \`a la} CLOS (Common Lisp Object System). In fact, the proposed extension is much closer from the objects one can find in Dylan, since this language is already a tentative to merge CLOS notions in a Scheme like language {\cite{Dylan}}. \stk object extension gives to the user a full object oriented system with multi-inheritance and generic functions. Furthermore, all the implementation rely on a true meta object protocol, in the spirit of {\cite{AMOP}}. This model has been used to embody all the predefined Tk widgets in a hierarchy of Stk classes. \subsection{Class hierarchy} With the \stk object system, every Tk graphical object used in a program such as a menu, a label or a button is represented as an object in the Scheme core. All the defined {\stk} classes build a hierarchy which is briefly described here. Firstly, all the classes shared a unique ancestor: the {\em $<$Tk-object$>$} class. Instances of this class contain informations which are necessary to establish a communication between the Scheme and Tk worlds. Objects of this class have two main slots named {\tt Id\index{Id slot}} and {\tt parent\index{parent slot}}. The {\tt Id} slot contains a string, normally generated by the system, which correspond to a (unique) variable name in the Tk world. The {\tt parent} slot contains a reference to the object which (graphically) includes the current object. Normally, end users will not have to use direct instances of the {\em $<$Tk-object$>$} class\footnote{ All classes whose name begins with the ``Tk-'' prefix are not intended for the final user.}. The next level in our class hierarchy defines a fork with two branches: the {\em $<$Tk-widget$>$\index{Tk-widget class}} class and {\em $<$Tk-canvas-item$>$\index{Tk-canvas-item class}} class. Instances of the former class are classical widgets such as buttons or menus since instances of the later are objects contained in a canvas such as lines or rectangles. Tk widgets are also divided in two categories: {\em $<$Tk-simple-widgets$>$} and {\em $<$Tk-composite-widgets$>$}. Simple widgets are directly implemented as Tk objects and composite ones are built upon simple widgets (e.g. file browser, alert messages and so on). A partial view of the \stk hierarchy is shown in Figure~2. \begin{figure*} %\centerline{\psfig{figure={Fig1-1.idraw},height={2.00in},width={2.00in}}} \centerline{\psfig{figure={hierarchy.eps},width={5.00in},width={5.00in}}} \caption{\em A partial view of \stk hierarchy} \vskip2mm \hrule \end{figure*} \subsection{Basic notions} This section describes basic concepts of our object extension on a small example. Definition of a new object class is done with the {\em defclass} form. For instance, {\small \begin{verbatim} (defclass person () ((name :initarg :name :accessor name (age :initarg :age)))) \end{verbatim} } \noindent defines a person characteristics. Two slots are declared: {\tt name} and {\tt age}. Characteristics of a slot are expressed with its definition. Here, for instance, it is said that the slot {\tt name} can be inited with the keyword {\tt :name} upon instance creation and that an accessor function should be generated for it. Creation of a new instance is done with the {\tt make} constructor: {\small \begin{verbatim} (define p (make person :name "Smith" :age 42)) \end{verbatim} } \noindent This call permits to build a new person and to initialize the slots which compose him/her. Reading the value of a slot can be done with the function {\tt slot-value}. For instance, {\small \begin{verbatim} (slot-value p 'age) \end{verbatim} } \noindent permits to get the value of slot {\tt age} of the {\tt p} object. Setting this slot can be done by using the generalized {\tt set!} defined in \stk: {\small \begin{verbatim} (set! (slot-value p 'age) 43) \end{verbatim} } \noindent Since an accessor as also been defined on the {\tt name} slot, it can be read with the following expression: {\small \begin{verbatim} (name p) \end{verbatim} } As before, slot setting can be done with the generalized {\tt set!} as in {\small \begin{verbatim} (set! (name p) 43) \end{verbatim} } \subsection{Tk classes} Now that basic concepts have been exposed, let come back to how using Tk with the object layer. In our model, each Tk option is defined as a slot. For instance, a simplified definition of a Tk button could be: {\small \begin{verbatim} (defclass