Around 1997 I had did quite a bit of programming in the Tcl language, as part of an IDE project at Cygnus. The project failed, for several reasons, but here I’m going to write about Tcl.

I don’t hear much about Tcl these days, although it was fairly popular in its day. Tcl is a highly dynamic interpreted language. It is easy to embed the Tcl interpreter into a C program. The Tk system, which is written in Tcl but is logically independent of it, is a very clever way to easily write a GUI program. Unfortunately, despite these advantages, Tcl is a mess of a language.

In Tcl, everything is a string. Tcl has list and associative array operations, but they all operate on strings with a specific syntax. The program itself is a string: you could construct new procedures on the fly, and annotate variables. This makes the language very powerful. It also makes it very confusing.

When everything is a string, type checking is completely impossible. It’s very easy to have a list and accidentally use a string operator on it. Everything will work fine, except you won’t be able to pull out the list values as expected. You might think that is not so bad–after all, in Lisp everything is a list, and that works well. But in Lisp, atoms are not lists, and atoms have a type: you can’t apply a string operator to a number. In Tcl the atomic unit is the character, and that doesn’t have a type. Applying a string operator to a number works fine, because a number is just a string of characters which happen to be digits. So when I say that type checking is impossible, I don’t just mean the ordinary lack of static type checking for a dynamic language. I mean that even at runtime there is no type checking.

Because everything is a string, quoting becomes essential. Tcl has various quoting mechanisms: double quotes create a simple string, square brackets create a string formatted as a list which is then normally executed as code, curly braces create a string formatted as a list which is not executed. Within a string, square bracketed lists are executed and variables with a leading dollar sign are interpolated. I’m sure I’m forgetting some aspects. Within such an environment, a detailed understanding of quoting becomes essential. Unfortunately, the only comprehensible way to quote actually involves using square brackets to invoke the list function. In other words, although everything is a string and it should be very easy to stick things together when that is what you want to do, in any scenario which is even slightly complex you have to start writing list operations in order to build your strings. Even then I recently wrote some Tcl code with seven consecutive backslashes, admittedly in a complex use case. That’s too much for easy reasoning, and in practice requires trial and error to get right.

I believe that Tcl has namespaces these days, but when I used it did not. That made it a poor choice for programming in the large, because all functions and variables lived in the same namespace. Because everything is fully dynamic, redefining a procedure causes no error. You don’t discover a namespace collision when you load the program, you only discover it when trying to figure out what went wrong.

The Tk system, as I mentioned, is a very clever way to write a GUI. it lets you write very simple code with windows and buttons and text input and so forth. These days most people would write some HTML and run it in a web browser, but Tk is a more powerful environment, and you can write everything in the same language, unlike the browser’s mix of HTML, Javascript, and server-side PHP or whatever. Tk is cross-platform.

Unfortunately, Tk too has a fatal flaw: because your GUI is produced by a simple program, your programmers have to change your GUI. When a UI designer wants to move a button, the only way to do it is to change the program. And Tk’s layout procedure does a lot for you automatically, which in practice means that it’s a pain to do anything else. The effect is that a Tk program always looks OK but never looks good. This effect is exacerbated by the fact that a Tk program looks kind of the same on any platform, which means that it looks unusual on any platform. For our IDE work we spent a fair amount of time building Tk interfaces to standard Windows objects, so that the programs would look sort of OK on Windows. In other words, Tk winds up being a great prototyping system, but a terrible system to use for your final program.

Despite all these awful characteristics, I have to say that the actual Tcl implementation is great. It’s platform independent, has a nice event loop, the code is easy to read and easy to modify. The core library provides system independent facilities which are well designed and well implemented. Unfortunately a good implementation can not overcome a poorly designed language.

So there you have it: a brief overview of language design gone wrong.


  1. fche said,

    March 31, 2011 @ 9:36 am

    All true. Reminds me of and of the “foolish consistency …” famous quote.

  2. ppluzhnikov said,

    April 6, 2011 @ 9:32 am

    Tcl was also intended to be easily embeddable extension language. “Everything is string” made it really easy to create extension points in Tcl.

    The Tcl interpreter weighted in at only ~50K of code/data, when GNU Guile weighted in at over 1M (which we deemed unacceptably high at the time when 8MB total RAM was considered a very “beefy” machine).

  3. pooryorick said,

    October 20, 2012 @ 12:26 am

    This post mis-characterizes most of the aspects of Tcl that it attempts to describe. In particular, the comment about seven consecutive backslashes is a strong hint that Ian didn’t grasp the elegance of Tcl quoting. This happens when people come to Tcl steeped in other language traditions, and attempt to apply those traditions to to Tcl, which is a different sort of creature. With all due respect to Ian, each of the criticisms in this article indicate that he just didn’t stick with Tcl long enough, or perhaps look into it deeply enough to resolve his misunderstandings of the language. More info at

  4. Ian Lance Taylor said,

    January 4, 2013 @ 8:27 pm

    I stand by my criticisms, but I don’t want to get in a back and forth about the language. I do want to note that I worked with Tcl for about 18 months. I think that I stuck with it long enough and I think I looked at it pretty deeply. If you look at comp.lang.tcl around 1997/98 you’ll see various minor patches that I sent in for Tcl and Tk, though I don’t know how many were adopted.

  5. pooryorick said,

    April 25, 2013 @ 11:46 pm

    The fact that this article is about Tcl before it had namespaces implies that it is just as obsolete as those old versions of Tcl. Much has changed in the intervening decade. Quoting is often implicit in Tcl, meaning that it gets out of the way. Where it is explicit, I think that it can be objectively proven to be more regular and simple than *any* other language. There is no such thing as Tcl code that requires seven consecutive backslashes, but there are plenty of people who are, for some mystifying reason, laboring under such misconceptions. Tcl quoting can be very frustrating if one insists on applying the rules of some other language to it, but those who have caught the Zen of Tcl syntax rarely look back.

  6. pooryorick said,

    August 18, 2013 @ 8:48 am

    Regarding the comment, “When everything is a string, type-checking is completely impossible”: The issue here isn’t really about “everything is a string”, which is a very nuanced concept in Tcl, but about the fact that types must be checked dynamically by the command receiving the arguments. The same is true of Objective-C, which has proven itself to be eminently useable as a general programming language. From the Wikipedia article on Objective C: “In a Simula-style language, the method name is in most cases bound to a section of code in the target class by the compiler. In Smalltalk and Objective-C, the target of a message is resolved at runtime, with the receiving object itself interpreting the message. A method is identified by a selector or SEL — a NUL-terminated string representing its name — and resolved to a C method pointer implementing it: an IMP. A consequence of this is that the message-passing system has no type checking. The object to which the message is directed — the receiver — is not guaranteed to respond to a message, and if it does not, it simply raises an exception.” So Ian’s criticism of this point isn’t specific to Tcl, but rather reflects his preference for Simula-style languages like C++.

  7. konz said,

    July 24, 2014 @ 6:26 am

    Honestly, TCL quoting is defined in the TCL man page (e.g.,, which is not particularly long, and devoted entirerly to the parsing/quoting of the language.

    The parsing is broken down into 12 rules, all of which should be familiar to C and Bourne Shell programmers. Ousterhout painstakingly designed this to avoid Bourne Shell pitfalls.

    {} quotes are like ” quotes in Bourne shell, except that they nest, and that they cannot be embedded in a larger word.

    [] means evaluate recursively, like Bourne backquotes, except that they nest, like $(), and that no new execution environment is created, i.e., modifications to variables are visible to the invoking script.

    “” are like C quoted strings, except that variable and recursive evaluation are performed within.

    Backslash quoting works as in C.

    Variable expansion does not reparse the arguments, i.e., no Bourne field splitting.

    The comment character is #, so #! works. Similar to make(1), but in contrast to Bourne sh(1), a backslash newline continues the comment, so you can hide a sh exec in a TCL comment.

    The only mildly unusual thing is the {*} operator (a newish addition), which interpolates the elements of the following list argument in a safe way; it does something akin to Bourne field splitting. This eliminates the need to use the list function to quote arguments.

    The fact that TCL programs are themselves representable as TCL data (homoiconic) makes it eminently useful for meta-programming. The proc overwrite feature is a feature, not a bug: e.g., a commercial program I use generates a function to initialize an embedded target board via a HW debugger. This function calls a small set of other functions (memory read/write) with various arguments. By overwriting the memory read/write functions, I can for example generate C code to perform the same thing.

    A commercially supported debugger is available, which greatly aids development.

    So I side with pooryorick: I find your dismissal of TCL premature and uninformed.

  8. konz said,

    July 24, 2014 @ 7:10 am

    Slight correction: “” is like Bourne Shell “” quoting, except that C backslash sequences are supported.

RSS feed for comments on this post · TrackBack URI

You must be logged in to post a comment.