Tcl is a programming language - a scripting language in fact. It has been around for fifteen years. Most programmers have never heard of it, a few people like it, a few don't. Below are my notes on what I consider useful and valuable about it. If you want religious statements, a side-by-side comparison with <insert-your favorite-language>, or a list of what's wrong with it: sorry, you'll have to go elsewhere...
Tcl's #1 strength has to be its dynamic datatypes, i.e. the lack of having to specify what type a value is: integer, string, list, etc. In static languages such as Java and C/C++, types are set at compile time. There are a number of variants of dynamic data types, which all scripting languages seem to have in common. In Perl, values have a type, but some of them can change depending on use (e.g. adding string representation of numbers). In Python, each value has a fixed type which can determined (ints/strings are immutable, lists/dicts are mutable). In Tcl, values do not have a fixed type - it depends entirely on usage.
Note that dynamic datatype is not the same thing as runtime typing, which is about being able to store differently-typed values in variables and other containers.
Is type-less coding, i.e. the combination of runtime typing and dynamic datatypes, a good thing? Just asking this is probably the easiest way to start a fight amongst programmers. I'll just summarize that after over 30 years of programming, I've seen many sides of this and consider the answer to be "yes". A lot of algorithmic code and a lot of administrative code (in the sense of administering data) does little more than pass around data without actually acting upon it. All of that just works regardless of what information is represented by each data value. Databases, GUIs, even something as "computational" as sorting and searching - it all consist of a lot of code which need not deal with separate types. Type-less code pushes the burden of comprehensive testing forward, but tends to continue to work unaltered when software evolves.
Ok, by now I will probably have alienated all Java and C/C++ programmers. Soit.
The way Tcl does type-less coding is often summarized as "everything is a string". This is an effective way to communicate the essence of this approach, even though it's not an accurate representation of what really happens inside, technically.
If everything is a string, then it can be shown on the screen, it can be stored and loaded back in, and it can be passed across the network without any further programming. And that's exactly where Tcl and Tk have gone.
Data structures require some care in this model. Lists are strings with specific conventions (essentially "things separated by whitespace", though the actual representation is a bit more sophisticated and able to deal with arbitrary textual and binary data). Lists can be used for structural aggregation and for indexable collections, and can be nested to form trees.
Pointers and references are powerful constructs, but can also a source of hard-to-find bugs when side-effects are allowed. Purely functional languages (of the "clean" type) disallow it entirely, and even good old Lisp went out of its way to prevent in-place alteration.
Tcl addresses this by offering a single mutable mechanism, as an associative array. Arrays are named, taking strings as keys and strings as values. The only way to "reference" an array, is to pass around its name.
One consequence is that it is totally impossible to create loops of references. Loops simply cannot be created, and reference-counted memory management need never deal with cycles.
Tcl uses copy-on-write everywhere in its implementation. In terms of programming, this means that nothing will change underneath you as side effect, yet memory is used efficiently. This lets you write a loop over a list, whereby you can safely delete elements and not get bitten by side-effects. With extensive and safe data sharing going on behind the scenes.
The exception to copy-on-write is the one mutable mechanism Tcl has: associative arrays. Arrays can change "underneath you". This is not an oversight but a controlled way to make mutable data work, and it comes with "traces" - a way to detect and act on any array access or change.
Tcl's "traces" are not a gimmick in the style of "let's add some change trigger capability, since it so neat" but a very fundamental part of the data model, which brings together immutable type-less data, mutable arrays as aggregators of state, and an event-like access and change control mechanism to manage transitions.
Tcl is one of those languages (along with Scheme and Forth) which are well-suited for creating small domain-specific languages. The reason for this is its total absence of syntax and parsing. When a command is invoked, the arguments are handed over to it - if these are enclosed in braces, then virtually no processing takes place. That means one can define a command which takes a string and interprets it in some very domain-specific way.
Taking this in another direction, Tcl commands are really just groups of words and symbols. It is very simple to define a set of new commands and then "program" in the new language of these commands. Nothing special needs to be done to process a set of lines of which the first word is one of the newly-defined commands.
Little languages are so easy to define in Tcl that it becomes second-nature. This means that the abstraction levels used in Tcl can be extended on the fly.
Scripting is based on the premise that a lot of software development takes place at the "glue" level, with a way to easily tie into existing and new C/C++ code when needed. This covers both the need to link to existing functionality and a huge set of libraries, and the need to write very processor-intensive tasks in C/C++ so they can be "compiled down to machine code".
Tcl neither excels nor lags in this area, it simply has the right capabilities. With tools such as SWIG and Critcl, it is very simple to step out of the language and into whatever the world around it has to offer.
The ability to code at multiple levels of abstraction, yet stay within one language for the overall design is a fundamental advance over the monolithic languages trying to be everything for everyone. All scripting languages share this advantage.
A relatively new development in Tcl is the addition of a Virtual File System layer to the core. As a result, all file-system I/O requests made in Tcl can be intercepted and handled in unusual ways. The most popular one is to deflect file system calls to access data stored inside a "Starkit", a single-file packaged version of a Tcl application - with all scripts, data files, images, and such "wrapped up". The result is an application which runs from an easily-shippable single file.
Starkits add platform independence, single-executable variants called "Starpacks", and the ability to carry binary extensions in them for more than one platform. This is not just a convenience for delivering large-scale scripted applications - it essentially removes several steps from the development -> delivery process and gets rid of installers and uninstallers.
It's easy to dismiss Tcl on all sorts of grounds.
Tcl has no syntax - Nothing will ignite discussion amongst programmers more than syntax. Doing so is a common excuse to ignore semantics. It's like saying that a car cannot be worth looking at because the seats are red. It's also very easy to ignore the fact that most of Tcl's syntactical design is not based on personal choice but a consequence of its core design. When everything looks like a string, then so does Tcl code itself. Not being a formally parsed language is what allows Tcl to be used as a little language. Getting a workable "comment" notation in there was not an afterthought but a careful compromise, based on what could be fitted in.
Tcl is not object-oriented - Everything is OO these days. Tcl can be dismissed as "not OO" by looking at its core data model. Yet Tcl is fully OO at the command level, as Tk's widgets illustrate. In fact, Tcl's trouble with OO is not the lack of it, but the fact that too many "little OO" extensions are available. As a result, none has surfaced as being the "official" one. And people just go on slapping together and tweaking their own OO designs - which turns out to be trivial. There is one important comment to be made about Tcl's OO-ness: Tcl is more suited at OO in the large than OO in the small. Fine-grained "an int is an object" OO would not fit well in Tcl. Everything is a string, after all. Then again, since a string is an object, one could argue that Tcl is 100% OO.
Tcl is slow - This is one of those fallacies which just keeps coming back. It's based on the way Tcl worked until 5 years ago. It assumes that if everything is a string, then things like arithmetic and list indexing must be grossly inefficient. It ignores the fact that Tcl uses a dual-representation design and internal caching to completely side-step most of these issues.
Tcl does not scale - Perhaps this is based on the reasoning that if Tcl is dynamic (errors happen at run time), has no syntax, has no object oriented encapsulation, and has no performance, then it must be the worst possible language to build really large projects with. It turns out that not only are each of these assumptions false, but the lack of side-effects makes Tcl in fact extra-ordinarily well suited for large-scale designs. Huge systems have been built with it - and are kept in Tcl today because of its stability, maintainability, ease of training, and scalability. Some systems run for years on end and are modified in-place without ever taking them down.
Tcl/Tk is not "en vogue". Nobody gets hired for picking Tcl, these days. There's a small community of users on the web, who band together to provide a lot of enthusiastic help to whoever chooses to get involved, but it's hard to ignore that there is a bit of silence and unease when it comes to Tcl's "place in the world". That's unfortunate. I hope the above helps make it clear that when hype and prejudice are left out of the equation, a skillfully designed and implemented set of trade-offs can be found inside Tcl. A solid open source engineering achievement.
Does that mean Tcl deserves a better fate? I have no idea. Fates are not decided on merit or on hearsay alone. Vested interests, prior investments, rate of change, previous experiences, perceived risks, majorities - these are all (valid) determinants when deciding what tool is best for a job.
May the above help you assess Tcl effectively. No more. No less.
© December 2003