Version 57 of TCL for beginners

Updated 2015-09-02 13:37:44 by pooryorick

Tcl for Beginners, is another introduction to Tcl

See Also

Dodekalogue
foreach
A simple and powerful command that is used extremely often
gotcha
Why can I not place unmatched braces in Tcl comments

Tcl is All about Commands

Tcl works by processing commands. In this regard, it's similar to an operating system shell like DOS or bash. Each line of a Tcl script is a command, and the first word of each line is the name of the command, and any other words are arguments for the command. Tcl looks up the code associated with that name and invokes it.

In DOS, for example, to list the contents of a directory you would type:

dir c:\path\to\folder

in Tcl you would write:

glob /path/to/folder/*

glob is a command, and has a purpose analogus to the dir command in DOS.

[glob] is one of the commands available in Tcl.

Commands are Made of Words

Another useful command is [puts], which, like the echo command in DOS, prints things out on the screen:

puts Hello

A mnemonic device for [puts] is put string.

In the command above, there are no quotes around Hello. No quotes are needed in Tcl because all words, including the names of commands, are just strings. In fact, in Tcl, everything is a string. Because of this, quotes are not used to signify that something is a string - that's already a given. Instread, quotes, braces, and backslashes are used to take away the special meaning that some characters have. Whitespace normally has a special meaning to Tcl, since it separates words in a command. When whitespace is part of the word itself, we use one of these quotes, braces, or backslash to escape that whitespace.

There are commands that interpret words as numbers in order to get some math done, but it's up to each individual command to decide how it wants to treat any particular word. Tcl makes no distinction.

Escaping Interpretation

[set] only takes two arguments. Therefore, this code

set foo good afternoon

will result in

error: wrong # args: should be "set varName ?newValue?"

We need to tell Tcl not to consider those spaces as word separators, but as part of the one word that makes up the argument to [puts]. Tcl provides quotes, braces, and backslashes for this purpose. The following three commands are equivalent:

set foo good\ afternoon 
set foo {good afternoon}
set foo "good afternoon"

Braces only have this special meaning when they are at the beginning of a word. In the middle of a word, they're just braces.

Not even newlines can stop braces:

puts {This is a whole
   paragraph inside braces.  Braces just
   don't quit until the matching closing brace
   is found.  Backslashed \} braces don't close it Off.  Neither
   do "Quotes".  {other matching braces} are OK, too.  But finally,
   we get to the closing brace.
}

Using Variables

Use [set] to set the value of a variable:

set greeting Hello

To get the value back out of a variable use a dollar sign. For example, to print Hello:

puts $greeting

This works even if there is white space in the greeting:

set greeting {Hello There}
puts $greeting

That's because Tcl substitutes the entire value of the variable into the the spot where $greeting was.

Command Substitution

Variable substitution isn't the only substitution game in town. There's also command substitution. This is done with square brackets. To print Hello to the screen using command substitution:

set greeting Hello
puts [set greeting]

When [set] only gets one argument instead of two, it returns the value of the variable instead of setting it.

Notice also that we just used the name of the variable without prepending a dollar sign to it. If we had prepended the dollar sign, it would have been equivalent to typing set Hello, in which case [set] would have gone to find the value of the variable named, "Hello", failed to find it, and returned an error.

Knowing that, you should be able to make sense of the following code:

Set Hello Howdy
set greeting Hello
puts [set $greeting]

What will be printed to the screen? That's right:

Howdy

Extra Credit (not really a beginner thing):

puts [expr $$greeting]

What will be printed? Yes, once again, it's

Howdy

Why? Hint: what does [puts $$] do?


Clif Flynt: When I'm teaching a class, I point out that

set set set

is a valid command, and that

set x set
set y a
set z b
$x $y $z

is a valid Tcl command to assign the value b to variable a. Looking at this makes the students stop and think. And stare at me like I'm crazy.

Commenting Code

Sometimes, particularly when we think we're doing something really clever, we want to add comments to our code so that other humans can make more sense of it. To do this in Tcl, we use the pound character, but only at the beginning of a command:

#puts {This line won't ever happen, because it's commented}
puts Whew!

Using Double Quotes

Braces inhibit variable substitution, command substitution, and most backslash substitution:

set name John

#warning - This next line won't substitute in John.  It just prints exactly
#what is in the braces, including the $.
puts {Hello $name}

When we want those substitutions, but we also need white space to just be white space, we can use double quotes instead of braces. Double quotes have the same purpose as braces, but also allow all substitutions:

set name John
set greeting "Hello, $name!  Hello again, [set name]!" 

As with braces, newlines inside quotes are just newlines:

puts "In double quotes, newlines
    are  just newlines.  If you escape a newline, \
    it disappears entirely.  Braces are just {braces},
    and other \"double quotes\" can be escaped. [
        set value {Command Substitution, which should really be called
        "script substitution"}
        set value
    ], is also not a problem at all.  Notice that there were multiple commands
    in that last command substitution, and the value of the last command is what
    actually takes the place of the entire command substitusion.  It doesn't
    hurt to escape \{braces\}, but it isn't necessary, either.  Escaping regular \letters
    doen't do anything at all to them.  An \a is just an a.  Finally, we get
    to the closing quote."
"

Using Backslashes

In addition to variable and command substitution, there is on other substituion device: Backslashes. They are used in Tcl in a manner very similar to that of C/C++. The following are backslash substitutions understood by Tcl:

\a
Audible alert (bell) (0x7)
\b
Backspace (0x8)
\f
Form feed (0xc)
\n
Newline, LF (0xa)
\r
Carriage-return, CR (0xd)
\t
Tab (0x9)
\v
Vertical tab (0xb)

The additional backslash sequences, \x and \u, are some documented in the Dodekalogue. They point to the fact that Tcl is not restricted to 8-bit characters, a limitation of some other languages.

If a \ is followed by up to 3 digits of numbers, than it is treated as an octal value for a character and the actual character is then substituted in its place.

Any other character following a \ is replace with itself. This is an 'escape' mechanism that enables you to make character just be themselves in places where Tcl would normally assign some special meaning to them:

puts "what do we mean when we say, \"word\"?"

If a backslash \ appears at the end of a line, then that line continues on to the next line:

puts \
  "Continued from the line above"

This is to allow a long line of code to be split into multiple lines if you run out of space in your text editor.

Word Expansion

Sometimes we need a way to tell Tcl to consider each word within a word to be an additional argument to a command. For example, if we have a variable that contains two words:

set attribute {name Bob}

The following would result in a four-word command, including the name of the command:

format {%s: %s} {*}$attribute

This is called "word expansion".

It's really All about Commands

The few rules that have just been described constitute the entirety of the Tcl language. Really! That's it. There's nothing more. The description above is a complete description of the Tcl language. There doesn't need to be anything more because those rules are entirely sufficient to create every other programming facility that exists in Tcl.

The only thing you will ever do in Tcl code is form commands. There are no control structures in the syntax because conrol flow can be, and is, implemented as commands. That's why Tcl really is all about the commands. There are two types of commands which may be considered fundamental: commands that create new commands, i.e., [proc], and commands that implement conditional constructs, i.e., [if].

Creating New Commmands

[proc] is used to create new commands.

proc greet {} {
    puts Hello!
}
======Commands that have been created this way are called procedures.

To create a procedure that takes an argument:

proc greet name {

    puts "greeting, $name!"

proc greet {name} {

To create a procedure that takes multiple arguments:

proc greet {first last} {

    puts "hello, $first $last!"

}

Since `[proc]` interprets its second argument as a list, the following works as well, but is not common:

proc combine {part1 part2} {

    set result $part1$part2

} combine hel lo

The result is:

hello

`[return]` can be used to be more explicit.  The following example has the
same result as the previous one.
[[`[return]`] can be used to be more explicit.  The following example has the

proc combine {part1 part2} {

    return $part1$part2

}

    set result $part1$part2
There's a special trick to creating a procedure that takes a variable number of
arguments.  If the last name in the list of arguments is `args`,
the new procedure can be called with any number of args, and within the
arguments.  If the last name in the list of arguments is `args`, [[`[proc]`]

proc greet {greeting args} {

    foreach name $args {
        puts "$greeting, $name!"
    }

}

To create a procedure that can be invoked with any number of arguments, or none at all:

proc count args {

    set length [llength $args]

proc {args} {

        puts "I was invoked with no arguments"
    } else {
        puts "I was invoked with $length arguments"
    }

}

And it works like that:

% count
** Conditional Constructs **

`[if]`, a necessary construct in any language, in Tcl is just another
command.  It takes a word that serves as the condition, and another word that
[[`[if]`], a necessary construct in any language, in Tcl is just another

if {1} {

    puts "1 is always true!"

}

Notice that `1` is braced, even though it wasn't strictly necessary.  Why?  To
advocate [Brace your expr-essions%|%good programming habits].  Until you learn
enought to know exactly when not to, you should '''always''' [Brace your
expr-essions%|%brace your expressions].


Here's another example:

if {0} {

    Anything at all can go here,
    even syntactically-invalid\{
    stuff, because Tcl will not attempt
    to evaluate this word, as the condition is false.

}



** What is a [list]? **

** What is a list? **
about [list%|%lists], except that some command might interpret words passed to them as
various things, including possibly lists.  It does specify, however, that a
about lists, except that some command might interpret words passed to them as
be strings.  Commands, in turn, are composed of words.  This strongly implies
script is a string, can be broken down into commands, which therefore must also
built-in `[list]` commands of Tcl accept a word as a list if and only
that the syntax of a command must be adequate to express a list.  There are
built-in [[`[list]`] commands of Tcl will accept a word as a list if and only
if the word could be parsed just as a command is parsed.  In

set a "A B C" lindex $a 0

The above commands return :

A B C A

However, not every string that can be interpreted as a command is a list.

[[`[lindex]`] returns the list element, located at the given index. Indices
start at 0.
set command {list {*}{one two three}}
lindex $command 0 ;# -> error: list element in braces followed by "{one" instead of space

result:

B

It's possible for a list to contain another list:

set a "A {B C} D"
lindex $a 1

result:

A {B C} D
B C

Remember that not all strings are lists.

Remember that not all strings are lists. that doesn't mean that any value given to split is a well-formed Although [split] can be used to convert any string into a list of words, that doesn't doesn't mean that any value given to [split] is a well-formed

DO

  • Do write lots of comments in your code about what your code does, what you tried that didn't work (and why, if known).
  • Do study the documentation and others' code to understand 'upvar', 'uplevel'.
  • Learn how to use exec so that you can start using Tcl to drive external programs
  • Learn how to use [exec] so that you can start using Tcl to drive drive external programs

DON'T

  • Don't have unescaped unmatched brackets ANYWHERE, including comments. Use a text editor that helps you by showing bracket matching.

Getting Stuff Done

  • tcllib is full of useful code. Try to use it as much as possible, a wide use of tcllib really saves time, and it is frequently updated.
  • If you need speed, be aware that Tcl can be extended easily (using C,C++...). Avoid writing your own extensions if existing ones can do the job.
  • Do split your code into different namespaces (and files) when it overcomes ca. a thousand lines.