Alexandre Ferrieux - July 98
Introduction
This guide was motivated by my experience with questions on the news:comp.lang.tcl usenet newsgroup. Very frequently, Tcl novices are lost in problems created by a poor architecture. Interestingly, Tcl has now gained sufficient maturity to allow fast and easy design of efficient and beautiful architectures. But, as any other full-featured programming language, it cannot prevent people from writing bad ones. Hence this guide.
Intended Audience
The intended audience is primarily 'Tcl novices': people with some previous exposure to programming in general (e.g., other languages), who are new to Tcl. Now I'm not saying it couldn't benefit 'Programming novices', who are discovering Tcl and programming at the same time (lucky them, wish I had something like Tcl to start with ;-), but it is more a 'concept paper' than a tutorial. The goal is to promote ideas, with the help of illustrative examples; for the corresponding recommended style/idioms, please look at real tutorials (there are plenty of good ones around - see e.g. http://www.purl.org/net/tcl-faq/ or http://www.phaseit.net/claird/comp.lang.tcl/tcl_tutorials.html ).
Scope
At the end of this article is a short list of simple ways of using Tcl for software reuse in a (possibly) heterogeneous, two-layer (explained below) context. It does not cover the simpler one-layer apps (where reuse occurs through the 'source' or 'require' commands), because IMHO it is sufficiently well-known...
White vs. Black boxes
Software architecture is all about reuse: nobody likes to reinvent the wheel.
There are two dinstinct approaches for reuse:
It is not hard to imagine the class of situations to which each one applies:
Interestingly, the now seemingly doomed white-boxing scheme has been endorsed (for years) by most OO languages, where a minimal prerequisite to object reuse is class-method oriented link API. As an example Sun's now dead CTI library (XTL) could only be accessed by its originating language, C++. Sometimes, things get even worse: you need to use the same compiler !
After a period of heavy support to the white-box OO framework, Microsoft itself acknowledged the failure of the model, and now puts its full weight into a black-boxing, language-neutral framework: COM.
It is thus clear that nowadays, black-boxing is the way to go in most cases. Now in this black-box context, a paradigm has emerged that allows one to build applications with minimal "mixing entropy": the Two-Layer model.
The Two-Layer model
In this framework, several independent and efficient functional "atoms" (building blocks) are made available to a single, general-purpose, highly readable integration language. The efficient atoms define the lower layer (L1), the integration language the higher one (L2).
The justification for this paradigm is fairly obvious: the two (rather incompatible) tasks of CPU-efficiency and "human-efficiency" are separately undertaken by the two layers, so one gets the best from both worlds.
The first and most popular example of this architecture is given by the Unix shells (sh, csh, and the like): human-efficiency is obtained via the super-simple command-line syntax, limited quoting/substitution abilities, and handy wildcards. CPU-efficiency is handled by handcrafted gems like grep(1) or sort(1), which are spawned as subprocesses of the shell.
The second, less obvious example of this is the late endorsement by Microsoft of the "scripting" paradigm within the COM/OLE automation framework. The result is less convincing, because of the heavy impact of GUI-only tradition (and also of bad design choices at early stages), but the idea is here.
Tcl is the third example along these lines. Its cross-platform scope makes it roughly a child of both previous examples, although the purity and orthogonality of its principles discard any possibility of a relationship with the second one ;-).
Unixians, read on !
All of the above is obvious to people familiar with Unix. It might interest them, however, to know that Tcl's inter-process communication (IPC) capabilities far outreach those from, say, the excellent Bourne Shell. One specific item, 'fileevent', is even unseen in any modern shell. Its power shouldn't be overlooked.
An ordered approach list for Tcl
Below is an introductory list of approaches for creating a modular two-layer Tcl application, ordered by increasing complexity & power.
Others are available - e.g. lower-level IPC like shared memory and message queues, or Tk-specific like 'send'. However, they are not described in this document because they're either less portable, or overconstrained, or too low-level for Tcl's shell spirit, or both.
List summary:
1) Child + exec
(See exec.n)
[Here and in the examples below, "xxx.n" or "yyy.3" are the names of the (nroff-based) Unix manual pages for Tcl, n being the 'scripting language commands' section, 3 the 'C functions'. On Mac and Windows, just type the name without extension in the Help application.]
1a) Synchronous
set result [exec cmd args 2>@ stderr]
Pros:
Cons:
1b) Asynchronous
set pid [exec cmd args 2>@ stderr &]
Pros:
Cons:
2) Child + fileevent
(See open.n, fileevent.n, close.n)
set f [open "|cmd args 2>@ stderr" r] fileevent $f readable "gotline $f" proc gotline f { if {[gets $f line]<0} { # it died ! close $f ; # catch to get exit status return ; # (see errorCode in tclvars.n) } # use $line ! }
Pros:
Cons:
Notes:
3) Loadable extensions
(see load.n, Tcl_CreateCommand.3)
load mydll mycall myargs ...
Pros:
Cons:
4) Linking libtcl to custom main()
(described in old JO draft)
<main.c>: ... Tcl_CreateCommand(...) ... cc ... -lmylib -ltcl -> builds a custom tclsh/wish extended with mylib's primitives.
Pros:
Cons:
Discussion and caveats
My strong suggestion here is to always make sure no approach earlier on the list than the one you choose can do the job. Occam's razor is a golden tool in software design (and in other areas as well ;-).
If you don't care for this dumb linear 'algorithm', here are a few rules of thumb to help you choose:
exec sh -c "dosomething > tmpfile;emacs tmpfile;rm -f tmpfile" &
Here, 'sh' waits for the end of the viewing operation because tmpfile serves no other purpose and should thus be deleted.
Thanks
My hearty thanks go to Larry Virden, for his thorough and insightful reviewing and editing, and also to Cameron Laird and Jean-Claude Wippler for their support about this paper.