Tool Command Language

Tcl -- Tool Command Language

Some important websites for more information and downloads:


Description of the Tcl language

Easily extendable script language which became most famous for the "TclTk GuiToolkit" and "TclExpect", as well as for easy embeddability, but it is increasingly used in other spheres. Some of its most unique features:


Cons of the TCL Language:


More on TCL

It is untyped and uncompiled [-- It does, however, utilize a bytecode compiler for efficiency now, making it about as slow as other scripting languages]. Tcl is much more a dynamic language than comparable scripting languages, and makes use of data as code model to great advantage.

TCL's main attraction is its small footprint, ease of network and GUI programming, event model, write-once-run-many (programmers usually have to go out of their way to make Tcl programs platform specific.)

It has a C API which makes embedding an interpreter easy (making it an EmbeddedLanguage). Passing data back and forth is easy, as is writing extension commands to the interpreter.

See http://wiki.tcl.tk/4364 (a two-player car racing game in 127 LOC) or http://wiki.tcl.tk/4448 (pages on TheTclersWiki) for examples of why some people like Tcl so much - brevity and automation of complex tasks.

Tcl was invented by JohnOusterhout while he was a professor at CalBerkeley.

Tcl has several implementations and is widely available on many platforms: Unix, MacOs9/ MacOsx, Windows, Palm OS, Windows CE, MSDOS, several realtime OS's, and as a browser plugin for Mozilla, Netscape, Windows IE. Tcl is also available as Jacl, a Tcl port to Java, thus it also runs anywhere Java runs. See: http://tcljava.sf.net


Hiring Tclers


Comments

Indeed, Tk is popular; it can even be accessed from Python and Perl (and Erlang). -- FalkBruegmann

Tk is a common reason Tcl is widely used. It is a very good GUI toolkit: lightweight, easy to use, simple to extend. It had a Motif look and feel,but was far simpler to use than Motif. It now uses the local look-and-feel of the platform on which it is running [- which is Motif on UNIX]. It is quite common that programs written on Unix/X11 runs unchanged on Windows and Mac (the same is true for Windows to Unix.)

Tcl as a language is highly dynamic and provides useful introspection facilities. If one writes idiomatic Tcl, using MetaProgramming techniques, rather than using it in the way one writes C or Pascal, one can write efficient and elegant programs. -- NatPryce

Nat, how are those techniques when used for Tcl? I've written quite a lot of Tcl/Tk code but I am not sure of what you are talking about. A friend and I were thinking about writing a Tcl module so we could make an abstraction layer for access to databases. The idea was creating something similar to DBI in Perl or JDBC in Java, but for Tcl (starting with postgresql). I got a nice design and when I sent it to my friend, he had already written a prototype, which created a 'database widget', similar to a Tk widget, indeed virtually indistinguishable. I found the idea fascinating and so we took that approach. Is this that metaprogramming you're talking about? -- DavidDeLis

Metaprogramming is writing code that, itself, writes code. The code that is generated represents application data. For example, a Tcl script could parse an XML document to create another Tcl script that has same structure as the document, and in which commands are named after the nodes of the document. The top level script can provide implementations of the commands in the "parse tree" to process the nodes. Evaluating the parse as a script then processes the parsed data.

So processing and parsing are performed by:

 proc node_NODE1 { ... } {
...
 }

proc node_NODE2 { ... } { ... }

...

eval [xml::parse $file]
The basic advantage of this is that, instead of interpreted code manipulating script-level data structures, you have C code (the interpreter) manipulating the data structures that represent the language.

See http://www-dse.doc.ic.ac.uk/~np2/patterns/scripting/


Functional composition

Here is a small but mighty example of metaprogramming: functional composition

 proc o args {
  proc [set name [info level 0]] x "
[join $args { [}] \$x [string repeat \] [expr {[llength $args]-1}]]"
  set name
 }
Maybe some explanations are necessary. A procedure named "o" is created (popular operator for function composition) which takes any number of arguments (indicated by the "args" special name). What the proc does is create another proc, with a name exactly as its creator was called (this is what [info level 0] returns), and exactly one argument, called x.

The body of this generated proc joins the args arguments (function names) with a space and an open bracket, indicating embedded evaluation, then the argument x - dereferenced by $ but deferred by the prepended backslash - and finally a sequence of closing brackets, one less than the length of the originally input args.

For example, consider the composition of three functions named "foo", "bar", and "grill":

 % o foo bar grill
 o foo bar grill
The returned result is the name of the generated procedure (not a true lambda, as it has a name, but coming close). It contains spaces, but that is no problem in Tcl, just quote accordingly. For instance, if we want to see the body of the generated procedure,
 % info body "o foo bar grill"
 foo [bar [grill $x ]]
See? A "nest of invocations" of the three functions has been created, and calling "o foo bar grill" with an argument just combines the three functions as intended. RichardSuchenwirth


More comments

More than a few programmers have been led into the world of Tcl because PhilipGreenspun chose to base his open-source ACS on AOLServer. Some very high volume web sites run AOLServer.


Tcl is a powerful language when we use it for CAD applications.

Tcl had, as its original purpose, to provide a common framework for writing the tiny languages that many applications have. In particular, think of things like spreadsheets, drawing programs, statistics programs - anything which requires one to issue commands or to take several actions - say a mail program for instance. Tcl is great for creating tiny languages with a lot of power. And its syntax is simple enough to teach to nonprogrammers. If they can get their brain around which brackets go where to express a simple if-then-else. Who would teach non-programmers to program in Tcl when there are Python and Ruby???

 read my mind and do what I mean
which in many other languages would have to be
 read("my", "mind", "and", "do", "what", "I", "mean");
And upvar is confusing enough to tie them up in knots for ever more. Tcl is a tragic case of a language design being severely degraded by a single feature.

FUD. Upvar is 1) not needed all that often, 2) a very simple concept: given the name of a variable, and optionally a context (global or stack level), upvar sets up an alias so you can access that variable (r/w) via a local name. It's indispensable for Tcl's by-value / reference-free approach to data structures. -- jcw

Yes. One should only use upvar when he wants to return two or more variables from a procedure and doesn't want to do that in a list.

To explain it even simpler: the [upvar] command is Tcl's way of CallByName, pretty equivalent to passing a pointer to a variable in C (only that you can specify the scope in which the name applies). It is mostly used to pass Tcl arrays (hash tables in fact), which can't be done by value. But it, together with [uplevel], also allows building all kind of debugging tools very simply. Here's an example - append an item to a list if it isn't there yet:

If that explanation were in the manual entry for upvar or in the tcl tutorial at http://www.tcl.tk, far less people would be confused by upvar.

 proc ladd {listVar item} {
upvar 1 $listVar list
if {[lsearch $list $item] == -1} {lappend list $item}
 }
 set aList {2 4 8 16} 
 ladd $aList 16 ;# doing it wrong; you should pass the name of
                 # the variable, not its value.
 ladd aList 32  ;# aList is now {2 4 8 16 32}.
 ladd aList 4   ;# aList is unchanged.
Another example, first in C:
 void f(int x, int *y) {
    *y = x;
 }
then the equivalent in Tcl:
 proc f {x _y} {
   upvar $_y y
   set y $x
 }
The difference to LISP (with its special forms and macros) is that you can always know whether you pass a value (as constant, or with "$" notation), or a variable name (via upvar) that may have side-effects, like changing the list, in the example.

In general, I suppose people experienced in languages of the Fortran/Algol/C/Java heritage may sometimes be bewildered by Tcl's concepts, but coming from LISP, one might very soon feel at home... -- RichardSuchenwirth


TclWar with RichardStallman

Several years ago, there was a big bruhaha between Richard Stallman and TCL fans. Richard claimed that TCL does not scale to large applications, and thus should be avoided in case small applications grow large. (Naturally, RMS perferred LispLanguage.) Personally, I suspect this depends on one's development style. If one uses a task-oriented and event-driven model, then "large application" is generally meaningless because you simply have a bunch of small programs that respond based on the state as recorded in files or databases with a few parameters passed between each script.

Unfortunately, RichardStallman was right but did not put his point across in a politically astute way. His argument was that Tcl is a rather poor foundation for a universal language with which to make applications scriptable, and that it would be better to embed a Scheme interpreter into applications and compile different scripting languages to Scheme at read-time. Now we have Parrot and .NET both trying to be virtual machines for different languages, both of which can be used as embedded interpreters. However, Scheme would be a more elegant representation than bytecodes.


More comments

I chose Tcl as my first (and, so far, only) programming language because it's simple and comprehensible; it's oriented more toward text and graphics (with the Tk toolkit) than toward maths and logic; it doesn't require the programmer to spend any time on loathsome tasks such as compiling; and yet you can do a whole lot of things with it.

-- David McClamrock??

Tcl is by far the simplest of the major scripting languages to extend with C modules. Especially using critcl. However, they all have their place. Even vbscript :) -- Pat Thoyts

Every time I have to do another project in Tcl/tk, I'm amazed at how easy it is to get my ideas into code quickly, and more importantly, correctly!

I don't like C++, as everything is sooo complicated. I do like Tcl/Tk, because it's not. -- Philipp


I am not sure what is happening in constructs like this:

  $t insert end "Hello World!"
The "t" variable is referencing some kind of widget (in this case a text GUI widget). What is happening in this case from a linguistical standpoint? How does it know which widget to operate on, especially if there are multiple text widgets?

the $t will be expanded to the value stored in t, which as you say is an instance of a widget. you have to remember that the first word on a line in TCL is a command (the rest of the words are arguments to the command) . the text command created a new command which enables you to interact with that text widget. so you call the 'interact with text widget foo' command, which happens to be the path of the text widget, it then uses insert end "Hello world!" to do that operation on itself. hope that made sense - there is more info in the help that comes with TCL -- JamesKeogh

I am still fuzzy on the steps the interpreter is taking. Tcl is not inherently object-oriented, so thinking of it in terms of an OOP language is probably misleading. The variable substitution may create a command that looks something like:

  .myTextWidget insert end "Hello World!"
But what exactly is ".myTextWidget"? It appears that ".myTextWidget" is a dynamically created function, not an object, but my documentation talks about it like it is an object in some places. Is this to sound "in fashion" to attract more Tcl users, or is it really an object?

.myTextWidget is a string, namely the name (actually the "path" in tcl jargon). It's all strings. Actually there may be some gyrations you can go through to get the underlying widget, but in general, with Tcl, you're dealing with names, not references. As an optimization, the compiler generates code that knows about types, widgets, what have you, but the closest analog to tcl is shell script. In the context above, i.e. beginning a line with the widget name, it's interpreted as if it's a function or object (with no references, there's really no difference). You can't go getting a reference to .myTextWidget though, except for its name - Tcl has CallByName semantics, and oh yes, you can abuse the hell out of those semantics if you try. Ultimately, however, these semantics tend to hinder the language from being able to implement advanced things instead of helping it, as was discovered in AlgolSixty (another language to have CallByName semantics)

But Tcl is supposed to follow the convention:

  command paramString1 paramString2 paramString3 ...
So it tries to execute ".myTextWidget" as a command. Is it actually "registered" as a command? For example, somehow put into the "command/function list"?

yes it is actually a command try this in wish:

 button .but -text "test"
 info commands .*
button creates a new command called .but, .but command acts on a particular button widget. "info" commands list all the commands with the given pattern. -- JamesKeogh {Did minor syntax editing}

  1. text .myTextWidget
  2. set t .myTextWidget
  3. pack $t
  4. $t insert end "Hello World!"
Let's see if I've got this straight. The first line creates a command called ".myTextWidget". The second line creates a variable "t" that contains the string ".myTextWidget" (for reference convenience). The third line ("pack") sends the string ".myTextWidget" to the "pack" command. The fourth line evaluates internally into:

  .myTextWidget insert end "Hello World!"
which executes the command created in line one. In line one, the Tk system creates both a command named ".myTextWidget" and puts the name ".myTextWidget" into an internal list. Line three uses the internal list, not the command (that was also created). Line four executes the command ".myTextWidget" that was created in line one. It is confusing because the Tk system creates two things which can be referenced: a command and an entry in an internal list. These are two different things even though they have the same name. My Tcl book never seemed to clarify this double action, leaving me to scratch my head.

Well, I suppose the Tk system can use the command list as the "internal list" I talked about to achieve the same thing. But, the point is that in some of the commands we are passing a string (widget ID) and in others we are using it as a command.


Regarding this roll-your-own UNTIL loop example from DynamicStringsVsFunctional:

 proc until {condition body} {
uplevel 1 $body
while {![uplevel 1 [list expr $condition]]} {
  uplevel 1 $body
}
 }
Why do we need a "list" construct? Why not just:

  while {![uplevel 1 $condition]} {...}
These are the tricky parts. "list" can be used to protect from double-evaluation, if $condition for instance contains parts which start with $ we don't want them evaluated by the interpreter but to let the "expr" command deal with them. "list" is generally used for this with "eval" and "uplevel" and similar things -- KristofferLawson

Why don't the "body" uplevel's also need to use "list"?

Because the "body" uplevels only get substituted once. Each time Tcl sees a command, it breaks it up into words (based on spaces and quoting). Then it does one level of expansion in those words (no expansion happens in {} quotes).

So, assume $body == {puts "Hello, world!"}, and $condition == {$a == 1}.

Tcl turns the "uplevel 1 $body" into:

  uplevel 1 "puts \"Hello, world!\""
The uplevel then does an eval on the 3rd argument, so the command runs as:
  puts "Hello, world!"
Just as we intended it.

The "while" command, on the other hand, gets passed with two words, the condition:

  {![uplevel 1 [list expr $condition]]}
And the body:
  { uplevel 1 $body }
The condition gets passed implicitly to the "expr" command (sort of; it won't call your expr if you redefine it). The "expr" command does variable, backslash and [command] substitution on the string. So:
  [uplevel 1 [list expr $condition]]
gets expanded recursively:
  uplevel 1 [list expr $condition]
then (because [list] quotes its operands):
  expr {$a == 1}
gets executed one level up in the stack context.

The {} quoting around the expr argument is required because expr does its own substitution. If you let uplevel parse it as:

  uplevel 1 expr $condition
the first level expansion will turn it into:
  uplevel 1 expr "$a == 1"
then uplevel itself would substitute:
  expr $a == 1
And if, for example, $a == "x y", the expr would fail with a syntax error when it does its own expansion, because it would try to parse:
  {x y == 1}


We use TCL where I work to make long-running network servers scriptable. The biggest advantage about TCL is that anyone that has ever written a beggining "intro to C" argc/argv style program knows exactly how to write a TCL command. Then the internal state and various options over behavior are exposed (via a socket attached to the global Tcl Interp) for our operational pleasure.


RichardSuchenwirth : Above it was said that "Tcl is not OO". There is more OO support in the making currently, but for a long while it has been possible to roll one's own OO in pretty simple ways. Example, a Stack "class" without any extra framework needed (both the class and its instances are implemented as namespaces):

 namespace eval Stack {variable n 0} ;#-- "class variable"

proc Stack::Stack {} { #-- Constructor variable n set instance [namespace current]::[incr n] namespace eval $instance {variable s {}} ;#-- "member variable" interp alias {} $instance {} ::Stack::do $instance } proc Stack::do {self method args} { #-- Dispatcher with methods upvar #0 ${self}::s s switch -- $method { push {eval lappend s $args} pop { if ![llength $s] {error "stack underflow"} K [lindex $s end] [set s [lrange $s 0 end-1]] } default {error "unknown method $method"} } } proc K {a b} {set a}

Testing in an interactive tclsh:

 % set s [Stack::Stack] ;#-- constructor
 ::Stack::1             ;#-- generated name of a stack instance
 % $s push hello
 hello
 % $s push world
 hello world
 % $s pop
 world
 % $s pop
 hello
 % $s pop
 stack underflow       ;#-- error message on empty stack
 % namespace delete $s ;#-- destructor


Some Tcl/Tk Links and Tutorials

Official tutorial: http://www.tcl.tk/man/tcl8.5/tutorial/tcltutorial.html

http://www.geocities.com/binnyva/code/tcl/tutorial/index.html

http://wiki.tcl.tk


SimplifiedWrapperAndInterfaceGenerator (SWIG) can be used to make calls to CeeLanguage or CeePlusPlus code.


See also TclTk, DynamicStringsVsFunctional, ActiveTcl, QuoteFreeLanguage


CategoryProgrammingLanguage CategoryTcl


EditText of this page (last edited February 2, 2012) or FindPage with title or text search