Tcl, some notes

Let’s have a topic about what makes Tcl unique.

In the Mindshifting May introductory video [link] Erik’s Tcl notes were:

Introduction

  • Originally developed by John Ousterhout whilst working at the University of California, Berkeley. Developed in the late '80s as an extension language for Electronic(s) design automation (EDA) applications (software tools for designing electronic systems such as integrated circuits and printed circuit boards) which were his professional focus.
  • Originally, it was envisioned that the Tcl code would be used as “glue”, and that all important functionality would be coded in C. But the Tcl language has evolved to be fully-featured in its own right.
  • Tcl, pronounced “tickle” is short for Tool Command Language
  • It was designed with the goal of being very simple but powerful.
  • General purpose, can be used for scripts, embedded, used for building websites or GUIs (via the Tk framework)
  • Multi-paradigm: object-oriented, imperative and functional styles are supported
  • Dynamic language
  • Open-source
  • Used in CISCO router GUIs, various manufacturing systems, NASA has used it on many occasions, Pixar, Boeing, Intel, NBC, and many more. Tk, the windowing toolkit, has been adopted by other “scripting” languages like perl/python/ruby. Expect, a tool to automate interactive CLI applications

Why it’s great

  • Very little syntax, just 12 rules and it fits on a piece of paper. Semantics are also relatively straightforward. Makes programs easy to read and learn
  • Simple concurrency via coroutines, which allows asynchronous code to be written like synchronous code
  • Built-in event loop for network programming and asynchronous file I/O
  • Mature, but still evolving

Standout features

  • Straightforward type system: everything is a string. “Everything is a string” was how Tcl used to be implemented. Now, under the hood, there is a robust type system, where the Tcl entity (be it a string, float, list, dictionary) has a type-specific representation as well as a string representation. This greatly improves the performance of Tcl code, as it no longer needs to convert back-and-forth from strings.
  • “Everything runs as commands”. There are no builtin commands. Tcl ships with a “standard library” of commands, including if and while, etc. It’s very simple tadd new control flow commands: for example an until loop. It’s also easy to override Tcl command.
  • Due to being compact, simple semantics and being implemented as a C-library, easy to embed

I’ll expand on some of these points.

Note, the 12 rules are here.

4 Likes

I don’t particularly consider Tcl as “mindshifting”. The syntax feels somewhere in between shell and Lisp. It’s a largely imperative language with procedures (i.e. functions). The data structures are pretty familiar: lists (arrays) and dictionaries (maps)

1 Like

“Everything runs as commands” is different from most non-lisp languages though.

You don’t x=5, you use a command set x 5

When you instantiate an object, the name of the instance becomes a command

set myDog [Dog new "Fido"]
$myDog bark

“Everything is a string” means that quoting is important. Like shell programming with double quotes and single quotes, Tcl has interpolating and non-interpolating quotes:

  • double quotes allow variable substitutions (and other form of substitution)

    set name Fred
    set greeting "Hello $name"
    puts $greeting
    # => Hello Fred
    

    Note that Fred does not need to be quoted: the set command takes one or two arguments, the second argument is just interpreted as the value.

  • curly braces are the non-interpolating quotes. No substitutions are performed

    set greeting {Hello $name} 
    puts $greeting
    # => Hello $name
    

    The proc command takes 3 arguments: the proc name, the argument list, and the body.

    proc greet {name} {
        return "Hello $name" 
    }
    greet Fred
    # => Hello Fred
    

    When you see braces used to enclose the arg list and the body, this is not special syntax: it is merely quoting the arguments to prevent variables from being substituted too soon.

Comments in Tcl are unusual. # is the comment character, and the characters following it to the end of the line(*) are ignored. So far so typical.

However the comment cannot be placed just anywhere. A comment can only appear where Tcl would expect to see a command word.

This is OK

# the user name
set name Fred

This is not OK (too many arguments to the set command)

set name Fred # the user name

But adding a semicolon makes it OK

set name Fred ;# the user name

I can’t explain precisely why Tcl works like this. It just how the parser works.


(*) “the end of the line” – the end of the line can be extended with a line contimuation

# this is a comment that \
  extends to this line.

It was once recommended to start Tcl scripts with this shebang formulation

#! /bin/sh
#\
exec tclsh "$0" "${1+$@}"
Tcl code goes here

sh does not honour the comment’s line continuation and executes the exec line. But Tcl sees the first 3 lines as plain comments and starts evaluating the Tcl code

Fortunately the “env” shebang is much tidier

#! /usr/bin/env tclsh

Ousterhout was awarded the ACM Software System Award in 1997 for Tcl/Tk (ref).

Other notable Tclers:

Tcl is losing out to Lua in this regard, I believe. The Tcl core is getting larger, so it’s not as small as it once was. And Lua’s syntax is a little more mainstream.

I’d add my 5 cents into the what makes TCL different:

substitutions aren’t just “in arguments”, it’s everywhere:

set command set
$command command proc
$command test {} { puts "test" }
test

will print “test”

Previously we used subst command to unroll lists into literal lists of arguments; since 8.5 there’s a language construct {*}:

set something {a b c}
my_proc $something ;# will call my_proc with a single agrument which is a list `{a b c}`
my_proc {*}$something ;# will call my_proc with three arguments, `a`, `b` and `c`

Also it was funny to see how dict command was implemented in pure TCL to retrofit into older versions. I used that in my code that was running in Cisco routers (which included TCL 8.3 with no dict).

1 Like