Tcl 2.1

Richard Suchenwirth 2002-12-18 - Late on March 3, 1990, Peter da Silva produced two shell archives (shar) that contained the full documentation for Tcl 2.1, and posted them to alt.sources. Thanks to the history awareness of SourceForge.net [L1 ] (and the friendly folks that uploaded the data), we can still today download Tcl 2.1 and, like in a time capsule, see how Tcl was when it was really young ;-)

The documentation of those times consisted of 18 man pages, 16 for the C functions, one for Tcl_Interp, and a single Tcl.1 for the language description (plus another, stream.5). It was a joy to read, more than 12 years after, and showed how mature Tcl was already at that time. Here are my notes on the differences I found.

"Tcl will eventually provide a mechanism for communicating between applications". It took Tk and send to fulfil that promise, but we still don't have a robust cross-platform solution...

Bracketed commands didn't need to be in one line: "newlines within brackets are treated as argument separators, not command separators". This has changed later, and we all know the backslashes to extend bracketed commands over more than one line. The current view is that the contents of brackets are a script, and hence the same rules apply.

"Double-quotes act the same as braces except that they cannot be nested". This means that no substitutions took place in double-quoted strings - later allowing them was a good decision, I think.

(This was one of my ideas that John picked up: I suggested that the way the shell distinguished single and double quotes was useful, and that Tcl should do something similar -- Peter da Silva)

"A Tcl expression has C-like syntax and evaluates to an integer result". No doubles, no string comparisons - but most of the operators were there already. I only miss ? : which makes concise decisions possible.

Tcl 2.1 built-in commands (left uncommented if like today's; an arrow -> marks what became of it later):

  • break
  • case string [in] patList body [patList body ...] -> switch but the default could be at any position. Glob-style matching only.
  • catch
  • concat
  • continue
  • error
  • eval
  • exec command arg1 arg2... [< input] - which is << today
  • expr - but integer only
  • file filename option - option could be: dirname executable exists extension isdirectory isfile owned readable rootname tail writable
  • for start test next body - next could contain a break
  • foreach varname list body - no multiple varnames or lists as of today
  • format
  • glob
  • global
  • if test [then] truebody [[else] falsebody] - no elseif
  • index value index [chars] -> lindex resp. string index
  • info option - option could be: args body commands cmdcount default globals level locals procs tclversion vars
  • length value [chars] -> llength resp. string length
  • list
  • print string [filename [append]]] -> puts
  • proc
  • range value first last [chars] -> lrange resp. string range
  • rename
  • return value - no return codes etc.
  • scan
  • set
  • source
  • stream handle option - option could be: open close gets puts name error eof tell seek -> separate commands
  • string option - option could be: compare first last match
  • time
  • uplevel - level with negative sign, e.g. uplevel -1; no upvar

Quite a mature language, it was! Here's what was added since then to the 8.4 command set: after append array binary cd clock encoding exit fblocked fconfigure fcopy fileevent flush incr interp join lappend load lreplace lsearch lset lsort namespace package pid pwd read regexp regsub socket split subst trace unset upvar variable vwait while - Some of these I'd sorely miss... An embedded language was apparently not allowed to exit its app; while was not a built-in, but the manpage says it can be added by using uplevel. while isn't that important, you can always do for {} test {} body -FW

The list of built-in variables was also very short, namely one: errorInfo. Finally, the short list of C functions as documented in 1990:

  • Tcl_Backslash()
  • Tcl_CreateCommand()
  • Tcl_CreateInterp()
  • Tcl_CreateTrace() - not available at Tcl level then
  • Tcl_DeleteCommand()
  • Tcl_DeleteInterp()
  • Tcl_DeleteTrace()
  • Tcl_Eval()
  • Tcl_Expr()
  • Tcl_GetVar()
  • Tcl_Merge()
  • Tcl_Return()
  • Tcl_SetVar()
  • Tcl_SplitList()
  • Tcl_StringMatch()
  • Tcl_WatchInterp() - register callback for interp deletion

A charmingly compact set... We've sure come a long way since then, but as I'm always interested in simplicity, it is fascinating to see how much power came out of so few commands and functions, twelve years ago...


What a blast from the past!

When I picked up Tcl 2.1, it was more limited than this: about the only file I/O built into the language was {print string ?filename? ?append?} or {exec cat filename}! It was only when embedded into John's "mx" editor that you could read or write part of a file. What you have here is a combination of the System V port of Tcl 2.1 with my stream extension, plus a Xenix port or rewrite of something I'd originally written on 2BSD at Berkeley.

John Ousterhout picked up the stream extension, split into multiple commands, and a few of my other ideas ended up in the core. But none of my code did: John rewrote everything, and his code was so clear and well written I couldn't possibly complain. When Karl Lehenbauer got involved, and John seemed to be abandoning Tcl, we took up the development of a new version that eventually became Tcl Extended. John seemed to take that as a challenge and again a lot of our ideas ended up in the core... arrays, for example, were mostly Karl's design. -- Peter da Silva


See chan for how the shattered parts of "stream" got reunited in Tcl 8.5 :^)