Updated 2011-04-27 01:58:06 by RLE

SS 25Jan2005:

It's well known that many Lisp dialects, like Scheme, have features that Tcl does not have. For example first class continuations, automatic tail call optimization, more speed. This page is instead my personal opinion about what in Tcl is better than in Lisp.

I used Scheme to write Web applications for some time before to switch to Tcl, mostly for the reasons below. Note that I like Lisp a lot, I'm a great fan of it. One reason why I like Tcl is that I find it similar to Lisp in some aspect, similar to what I enjoyed of Lisp, I mean.

This is my list of things I like more in Tcl over Lisp:

  • Tcl is a programmable programming language like Lisp, in both you can write new control structures, and more generally it's possible to specialize both the languages. But while in Lisp is usually needed to write macros, in Tcl you have to write normal procedures.
  • Lisp has types, more or less like Python and Ruby. For example in order to use a number as argument of a string manipulation function, there is to convert from one type to the other.
  • In Tcl serialization just happens for many types because almost everything has a string representation. You can write a Tcl list in a file just with: puts $fd $list. This is not possible in Lisp, where you need to perform serialization.
  • Lisp central data type is the list, while Tcl central data type is the string. Tcl also makes a lot of use of lists that are just special strings. In today's world, to have strings as base type is usually more useful, because many thinks like HTML, XML, Networking Protocols, are about strings more than they are about lists. To deal with strings in Lisp is not as natural as with Tcl. On the other side, Tcl lists features allow to exploit many programming paradigms used in Lisp. For example to convert a string into a list of characters, and manipulate it as a list when is more convenient.
  • The Tcl world is less fragmented. There aren't a big number of implementations of Tcl, and there is a bigger default library.
  • Tcl has built-in event-driven programming, integrated with the I/O library. To write complex networking programs with just what is provided in the core language is so simple it's funny.

Please feel free to comment, especially if you think some of the points are not fair.

--The #scheme room on irc.freenode.com responds thusly; comments please http://wiki.tcl.tk/13410
 <Catfive>There are still people that use Tcl?
 <xerox>Ok, got it.
 <forcer>slack_tcl: Argument 1, Macros: Tcl represents everything
   as strings (formally). That makes optimization horrible, and requires
   a runtime interpreter. Argument 2, auto-type-conversion: Nice for small
   stuff, leads to annoying bugs in bigger programs. Argument 3, serialization:
   Use WRITE to serialize data structures. Argument 4, Strings:
   A list is a compound data type, a string is not compound, but needs
   a parser to be so; the basi
 <forcer>c data type of a language should be a compound type;
   Scheme has wonderful support for HTML/XML, because HTML/XML
   is not about strings, but about structure, which Scheme can
   represent very well. Argument 5, less fragmentation: True
   (whether that's a pro or con is subjective). Argument 6,
   event-driven programming: True; Tcl has a better standard
   library than R5RS; most scheme implementations have a good
   one as well, and using cont
 <forcer>inuations, event-driven programming can be
   abstracted away, which is even better than a basic foundation,
   which also can be implemented easily in Scheme. ;-)
 <forcer>``Years ago at an X conference in San Jose,
   Ousterhout gave a talk on Tcl/Tk. I came away from the talk
   thinking "Man, what a poorly implemented Lisp interpreter that is!" (Mike McDonald)''

RS HTML/XML is of course about strings, which express structure; and Tcl can work on strings perfectly, as well as on the expressed structures when represented as nested lists... And lists are not just strings, at heart they are dynamic vectors of references to objects, which again can be lists, or integers, or doubles... but every object can be represented as a string, too.

What I like most about Tcl, compared to Lisp, is the simplification by unifying concepts:

  • commands work as functions, special forms, macros (well, sort of)
  • lists cover the uses of Lisp lists, vectors, arrays, structs...

SS my replies:

  • 1) Optimization is not horrible but via dual-ported objects with a well defined semantic. Interpretation is not needed, actually Tcl8.x is byte-compiled. Also I feel shocked that Scheme people are talking about implementation details instead to talk about abstraction power ;) In Tcl metaprogramming is more abstract, you always requires Tcl procedures for every kind of work, being it a new control structure, or a procedure to sum two numbers. in Lisp there is less abstraction because to do some work you need to perform a source level transformation, for others you need a function.
  • 2) In Tcl is less likely that auto conversion turns to bugs, because the auto conversion works checking that the format of the string is compatible with the destination type. This means that if I try to sum "12" with "foobar" there will be a runtime error because "foobar" is not a valid representation for an integer.
  • 3) WRITE: nice abstraction, but you are requiring a layer that do the conversion like any other language where objects are semantically typed.
  • 4) Note that in Tcl strings and lists are both central data types, for instance every Tcl list is also a valid Tcl command, but a list is in turn a string. In order to model the structure of HTML/XML a Tcl list is indeed more appropriate, but there are many other tasks when you need to work directly with the string: in this contexts variable/command interpolation, no type conversion, makes it a non problem. Scheme is truly generic, this makes it cool and ready to face every kind of problem in theory but there is a price for this: simpler problems are often more complex to solve in Scheme than in other languages with explicit support for such problems.
  • 5) This is very questionable, fragmentation may also mean faster evolution, but too fragmentation may just mean that there are far more Scheme implementation and wasted efforts than needed. Btw I'm not fully against fragmentation if it has a good reason, in fact I'm writing the Jim interpreter, an implementation of Tcl with some changes.
  • 6) Continuations: good point. Still event driven is many times a fast and comfortable way to model problems, the Tcl implementation of event driven programming is very abstract. For example with non-blocking sockets you can write to a socket without to care at all if it is writable or not and Tcl will try in the background to check for write buffer availability to feed the data to the socket when possible. Also the after command makes Tcl one of the few languages that support the notion of time in the default library in a decent way. Btw I agree this are features not about the language itself but about the library that can implemented in many other languages.

About Tcl being a bad implementation of Lisp, I don't think so of course. Surely Lisp was in the mind of John Ousterhout, as he wrote in the usenix paper that was shipped with the first versions of Tcl. Note that many users here think that Lisp in general and Scheme in particular is something of very interesting to look at. Many Lisp idioms, and bottom-up programming itself are the Tcl way to program too. Just Tcl tries to be more practical for many of us, supporting at the same time a mix of functional, imperative and object oriented programming, similarly to Common Lisp. Also many real world problems are simpler to solve because of more support inside the language. Of course there are many things that may be better solved using Lisp, especially when complex linked data structures are needed, or abstractions like continuations.

  • 7) ... also note that many features of Lisp that are not in Tcl may appear later or in a different implementation of Tcl. For example the Jim interpreter has closures (see Jim Closures), garbage collecting lambda, more functional programming support and other interesting features.