Tcl is an interpreted language. The main interpreter program is named tclsh or, depending on the installation, tclsh8.6 or tclsh86.exe on Windows.1 The tclsh program can be started in one of two modes: interactively or in batch mode. In batch mode, tclsh accepts a file name as an argument and will then load the file and execute each command in it before exiting. In interactive mode, tclsh presents the user with a prompt, much like a shell, from which you can type in commands to be evaluated one at a time. After evaluating each command, tclsh will print the result of the command, or any error message that was generated. To start tclsh in interactive mode, simply start it without any arguments.
As we mentioned in the introduction, Tcl was designed to be embedded into other applications. It should therefore come as no surprise that tclsh is not the only way of accessing a Tcl interpreter. Tcl is embedded into a number of different applications and devices, from CAD (Computer Aided Design) packages to network routers. However, there are also a number of other standard interpreter programs which might also be installed on your system. One example is the WIndowing SHell, wish. This is a version of tclsh that automatically loads the Tk graphical user interface extension. Other options are also available, providing more functional environments for developing and debugging Tcl code. One very popular choice is the TkCon (http://tkcon.sf.net/) enhanced interactive interpreter, written by Jeff Hobbs. The Eclipse IDE also offers good Tcl support, via the DLTK project (which also supports Python, Ruby and other ‘dynamic languages’). For writing longer applications, a good programmer’s text editor is worth acquiring. A number of IDEs and editors with support for Tcl are listed on the Tcl Wiki (see the Additional Resources section in the Preface).
The traditional starting place for a tutorial is the classic “Hello, World” program. Once you can print out a string, you’re well on your way to using Tcl for fun and profit!
The command to output a string in Tcl is the puts command. A single text argument after the puts command will be printed to the standard output device (stdout; usually the console). The default behaviour is to print a newline character (“return”) appropriate for the system after printing the text. Here’s an example of using the puts command to display some text. You can run this either by start tclsh interactively and typing in the command at the % prompt, or by saving the command into a file called hello.tcl and then running tclsh hello.tcl.
puts Hello!
If the string has more than one word, you must enclose the string in double
quotes (""
) or braces ({}
). A set of words enclosed in quotes or
braces is treated as a single unit, while words separated by whitespace are
treated as multiple arguments to the command. Quotes and braces can both be used
to group several words into a single unit. However, they actually behave
differently. In the next section, you’ll start to learn some of the differences
between their behaviours. Note that in Tcl, single quotes are not significant,
as they are in some other programming languages, such as C, Java, Perl and
Python.
Many commands in Tcl (including puts) can accept multiple arguments. If a string is not enclosed in quotes or braces, the Tcl interpreter will consider each word in the string as a separate argument, and pass each individually to the command. The puts command will try to evaluate the words as optional arguments, likely resulting in an error. Here is an example interactive session with tclsh, showing the correct ways of calling puts and an error that results from an incorrect call.
% puts "Hello, World!" Hello, World! % puts {Hello, World!} Hello, World! % puts Hello, World! can not find channel named "Hello,"
A command in Tcl is a list of words terminated by a newline or
semicolon. You can write a comment (i.e., a piece of text that
documents the program) by starting a command with a #
character. The
comment continues until the end of the line, ignoring any semicolons or other
punctuation. Tcl will skip any text in a comment and move on to the next
command. You can use comments to describe the intention of your code to other
programmers, or temporarily disable a command that you do not want to be
evaluated. Note: In Tcl, comments can only appear where Tcl would
expect a command to begin. You cannot, for instance, introduce a comment in the
middle of a command, or in the middle of a quoted string. If you wish to add a
comment to the end of an existing line, you can use a semicolon to first
terminate the command.
# This is a comment on its own line puts "Hello, World" ;# This is a comment after a command puts "Bad" # This will cause an error - no semicolon! puts "Line 1"; puts "Line 2"; # Prints two lines puts "Semi-colons inside quotes are ignored: ; See?" puts {... and within braces: ; See?}
A value2 is a piece of data that can be passed as the argument of a command, or returned as its result. In Tcl, every value (or term) is a string, i.e., a piece of text. This is in contrast to many other languages, in which values are sharply divided into different ‘types’, e.g., integers, strings, lists, and so on. In Tcl, it is up to individual commands to determine how to interpret the arguments that they are passed. For instance, one command might treat the string {a b c} as a list, while another treats it as a set (i.e., a collection without duplicates), while yet another might treat it simply as a string. Internally, Tcl remembers how commands have interpreted different values, so for instance if the string 3.14159 is always interpreted as a floating-point number, then Tcl will remember this interpretation and store an efficient representation of the number, identical to the representation used in most other languages. This allows Tcl to still be quite fast, while maintaining the flexibility that makes it such a convenient ‘glue language’. This property is often referred to as ‘everything-is-a-string’, or EIAS, within the Tcl community.
While all Tcl values are strings, there are a number of other elements to the language which are not values, and are not strings. We have already encountered one such entity: commands. Another very important type of object are variables. A variable is a named location in memory that can be used to store values. All non-value resources in Tcl are accessed via names: commands, variables, channels, and so on. While the name is a string, the underlying resource that it names is usually a more complex entity. You can assign a value to a variable using the set command:
set fruit "Cauliflower"
When set is called with two arguments, as above, it places the second argument (Cauliflower) into the memory space referenced by the first argument (the variable; fruit), overwriting any value that was already there. If the variable does not already exist then a new one is created with the given name. The set command always returns the new value of the variable, in this case the string Cauliflower.
The set command can also be called with just a single argument. In this case it simply returns the current value of the variable:
% set fruit Cauliflower
Because fetching the value of a variable is such a common task, Tcl has built-in syntax just for this operation: the $ symbol can be used in front of a variable name to retrieve the current value. This can even be used within a quoted string:
puts $fruit ;# Just prints "Cauliflower" puts "The fruit is: $fruit"
You cannot however use this within braces. The following code will print the literal string “The fruit is: $fruit”.
puts {The fruit is: $fruit}
This is the main difference between quotes and braces: braces prevent substitution. By default, Tcl’s $-substitution rules only allow variable names to consist of letters, digits, or underscores.3 If you want to have more complicated variable names, perhaps including spaces or other punctuation characters, you can use braces to tell Tcl where the end of the variable is:
set "My long variable" "Some value" puts ${My long variable}
A variable can be destroyed using the unset command, which takes a variable name as an argument and removes that variable, as if it had never been set:
% set x 1 1 % unset x % set x can't read "x": no such variable
You can also find out which variables have been created by using the info vars command4. This returns a list of all the variables that are currently defined in this scope. You can also pass a pattern to the command in order to restrict which variables are returned. Here we can see a number of special variables that Tcl defines automatically on startup:
% info vars tcl_* tcl_rcFileName tcl_interactive tcl_version tcl_pkgPath tcl_patchLevel tcl_library tcl_platform
In Tcl, the evaluation of a command is done in 2 phases. The first phase is a single pass of subsitutions. The second phase is the evaluation of the resulting command. Note that only one pass of substitutions is made. Thus, in the following command, the contents of the proper variable are substituted for $varName, and then the command is executed.
puts $varName
Assuming we have set varName to "Hello, World!", the sequence would look like this:
First $varName is substituted: puts $varName ⇒ puts "Hello, World!".
Then, the command is evaluated, resulting in "Hello, World!" being output to the console.
During the substitution phase, several types of subsitutions occur:
A command within square brackets ([]
) is replaced with the result
of evaluating that command.
Words within double quotes or braces are grouped into a single argument.
Variable references (with a preceeding $
) are replaced with the
value of that variable.
‘Backslash substitution’ is performed (see Section 1.4.1).
Double-quotes (""
) and braces ({}
) both serve to group multiple
words together into a single word in the command. The difference between them is
that braces prevent subtitution being performed on their contents, whereas
double quotes do not. Compare:
set a 10 puts "a = [set a] or $a" ;# prints "a = 10 or 10" puts {a = [set a] or $a} ;# prints "a = [set a] or $a"
Command substitutions can be nested, for example, given fictitious ‘readsensor’ and ‘selectsensor’ commands, we can write:
puts [readsensor [selectsensor]]
This will first evaluate the selectsensor command and then pass the result to the readsensor command as a single argument. The result of that command will then become the argument to puts. Note that only a single round of substitution is ever done, despite multiple commands being evaluated. This means that, for instance, if the selectsensor command returns a string such as ‘$someText’ this will be treated as a literal string and not substituted as if it was a variable reference. You can perform an extra round of substitution using the subst command if needed, but that is a rare requirement.
The result of a command or variable substitution is usually treated as a single
word in the resulting command. For instance, in the example above, the string
"Hello, World!" became a single argument to the puts command,
despite having a space in it, because it was the result of a variable
substitution. The only exception to this rule is the new {*}
operator
that was introduced in Tcl 8.5. This operator converts a list of words (such as
the result of a command or variable substitution) into a set of individual
arguments. Compare:
set x "a b c d" puts $x ;# => puts "a b c d" -> displays "a b c d" puts {*}$x ;# => puts a b c d -> error
The {*}
operator is an advanced feature that you generally won’t have to
use much when you are learning Tcl. The full behaviour of substitution and
evaluation in Tcl is described in the main Tcl.n manual page
[11], which you should read completely before starting any serious
programming with Tcl. The 12 rules given in that manual page completely describe
the operation of the Tcl interpreter, and you should try to read and understand
them before moving on. The rules can be quite subtle, however, especially if you
are used to other programming languages, so don’t be surprised if it takes a
little while to fully appreciate the details!
| ||||||||||||||||||||||||||||||||||||||||
Table 1: Backslash escape sequences. | ||||||||||||||||||||||||||||||||||||||||
In general, the backslash (\
) disables substitution for the single
character immediately following the backslash. For example, the string
‘\"
’ will be replaced with the literal character ‘"
’ (a double
quote), and will not be regarded as starting a double-quote string for grouping.
However, there are also a number of specific ‘Backslash Sequence’ strings which
are replaced by special values during the substitution phase, shown in Table
1. Backslash-newline (‘line continuation’) substitutions are
the only form that is performed within braces.
Here are some examples you can try in a tclsh interpreter session. Try to guess what the result of each will be using the rules before testing it.
set Z Albany set Z_LABEL "The Capitol of New York is: " puts "$Z_LABEL $Z" puts "$Z_LABEL \$Z" puts "\nBenFranklin is on the \$100.00 bill" set a 100.00 puts "Washington is not on the $a bill" puts "Lincoln is not on the $$a bill" puts "Hamilton is not on the \$a bill" puts "Ben Franklin is on the \$$a bill" puts "\n..................... examples of escape strings" puts "Tab\tTab\tTab" puts "This string prints out \nontwo lines" puts "This string comes out\ on a single line"
The Tcl command for evaluating mathematical expressions is expr. Many commands use expr behind the scenes in order to evaluate condition test expressions, such as if, while, and for loops. All of the advice given here for expr also holds for these other commands. The following sections are largely derived from the standard Tcl manual page for the expr command.
The expr command takes all of its arguments (‘2 + 2’ for example) and evaluates the result as a Tcl ‘expression’ (rather than a normal command), returning the value. The syntax of Tcl expressions resembles that of conventional mathematical notation, including various standard infix arithmetic and logical operators, bitwise operators, as well as functions like rand(), sqrt(), cosh() and so on. Expressions almost always yield numeric results (integer or floating-point values).
A Tcl expression consists of a combination of operands, operators, and parentheses. White space may be used between each of these; it is ignored by the expression processor. Where possible, operands are interpreted as integer values, otherwise it is treated as a floating-point number. Integer values may be specified in decimal (the normal case), in octal (using the prefix 0o), in hexadecimal (using the prefix 0x), or in binary (prefix 0b). For compatibility with earlier versions of Tcl, you can also use just a leading zero to indicate octal, but this use is discouraged in new code. Some examples follow:
% expr {1234} 1234 % expr {0o1234} ;# 1234 octal = 668 decimal 668 % expr {01234} ;# 1234 octal (old-style notation) 668 % expr {0x123f} ;# 123f hexadecimal = 4671 decimal 4671 % expr {0b11110000} 240
If an operand does not have one of the integer formats given above, then it is treated as a floating-point number (i.e., an approximate real number), if that is possible. Floating point numbers may be specified in any of several common formats making use of decimal digits, the decimal point (‘.’), the characters ‘e’ or ‘E’ indicating scientific notation, and the sign characters ‘+’ or ‘-’. For example, all of the following are valid floating point numbers:
% expr {2.1} 2.1 % expr {3.} 3.0 % expr {6e4} 60000.0 % expr {7.91e+16} 79100000000000000.0
Note that the comma ‘,’ is not a valid decimal point indicator in Tcl. The special values ‘Inf’ and ‘NaN’ (exact spelling) can also be used to represent floating point infinity and not-a-number, respectively.
If no numeric interpretation is possible, then an operand is left as a string, and only a limited set of operators may be applied to it. Some operations expect a Boolean truth value. Table 2 shows the valid Boolean values in Tcl.
| ||||||||||||||||
Table 2: Valid Boolean truth values. | ||||||||||||||||
Since Tcl version 8.5
Tcl can handle arbitrarily large integer values exactly. This is handled largely transparently for the Tcl programmer, with the internal representation of the number automatically upgraded to a format that is large enough to represent the value. For example, we can calculate 21000 as follows:
% expr {2**1000} 107150860718626732094842504906000181056140481170553360744 375038837035105112493612249319837881569585812759467291755 314682518714528569231404359845775746985748039345677748242 309854210746050623711418779541821530464749835819412673987 675591655439460770629145711964776865421676604298316526243 86837205668069376
The expr command understands the following logical (Boolean) operators (in descending order of precedence):
The following operators are used for standard arithmetic operations on numbers:
[expr {$x**$n}]
means xn.
The following operators are used to perform operations on the binary (bitwise) representation of integers:
% format %#hb [expr {~0b0101010101010101}] 0b1010101010101010
The following operators can be used to compare strings and to determine if a value is or is not an element of a list. Although listed separately, all of these operators share the same precedence.
[expr {$x in $xs}]
will return 1 if the value in
$x is a member of the list $xs.
Tcl supports the following mathematical functions in expressions, which you can
access using traditional mathematical notation, e.g., [expr {sin($x)}]
.
|
You can also access normal Tcl commands within expr using the usual
square-bracket syntax, e.g., [expr {[set a]+1}]
. Be aware, however, that
any further sub-expressions contained within such command calls must include a
further call to expr, as in:
[expr {[mycmd [expr {$x*2}]]+1}]
As of Tcl 8.5, you can now expose Tcl commands as functions within expr by
creating a command in a tcl::mathfunc namespace6, which would allow you to write the
expression as [expr {mycmd($x*2)+1}]
, which is much clearer.
One extremely common arithmetic operation is to simply increment a variable containing an integer. You could accomplish this simply using expr, as:
set x [expr {$x + 1}]
However, the operation is so common that Tcl builds-in a convenient short-hand, which is also slightly more efficient: the incr command. The syntax of incr is as follows:
incr varName ?amount? |
1 Throughout this book we will assume that you have the 8.6 version of Tcl installed, which is the latest version as of this writing. Differences to previous versions will be pointed out in the text.
2 More correctly, a term.
3 Two other forms are also allowed, which will be discussed in later chapters on namespaces and arrays.
4 The info command contains lots of useful sub-commands for inspecting the state of the interpreter. We will discuss others as we encounter them.
5 The format command here converts the decimal result into a 16-bit binary representation.