Tcl Part I · Module 1 · Introduction to Tcl
Programming vs Scripting
Tcl gets called a scripting language, usually in a tone that implies something lesser. This chapter deals with the label quickly, because the label is not very interesting — Tcl has procedures, namespaces, data structures and error handling, and it is a programming language by any test that matters. What is genuinely worth your attention is one behavioural consequence of how Tcl is run: it checks almost nothing about your program before it starts executing it. Lines one to three can produce correct output and line four can turn out not to be a command at all. Understanding that now is what makes the error chapters later in this module useful rather than alarming.
Foundation8 min readTclPart IFundamentalsExecution
Part I · Module 1 · Chapter 1.2 · Programming vs Scripting
1. The Label, Dealt With Quickly
People say "scripting language" to mean several different things, and they rarely say which:
- No separate build step. You edit a file and run it. There is no command you have to remember to run in between.
- Glue work. The language's job is to drive other programs rather than to implement algorithms.
- Small programs. A few dozen lines that automate something tedious.
- Dismissal. Not a real language, by whoever is speaking.
The first is a true and useful statement about Tcl. The second describes what Tcl is commonly used for, which is not the same as what it can do. The third is a statement about typical programs, not about the language. The fourth is not a technical claim.
Tcl has procedures, local and global scope, namespaces, lists, dictionaries, string and file libraries, an exception mechanism, and packages. Chapter 1.1 showed that its control structures are commands rather than grammar, which is unusual, but "unusual" is not "limited". By any test that distinguishes a programming language from a configuration format, Tcl is a programming language.
So the useful answer is: Tcl is a programming language that is normally used in a scripting style. The label is not worth arguing about. One of its consequences is.
2. The Consequence That Matters
Here is the whole chapter in one comparison.
In a compiled language, there are two distinct moments: the compiler reads your entire program and either rejects it or produces an executable, and then — later, separately — you run that executable. A misspelled function name is caught at the first moment. Nothing runs until the whole program has passed inspection.
Tcl has one moment. The interpreter reads your file and starts doing what it says. A command that does not exist is not a problem until the interpreter reaches it and tries to look it up.
That difference is not a nuance. It changes what a partial success looks like.
3. Edit, Run — There Is No Step Between
Put two lines in a file:
puts "starting"
puts "done"Run it:
tclsh greet.tclstarting
doneChange the text, save, and run the same command again. The new output appears. There is nothing to rebuild, no object file, no stale binary that might not match the source you are looking at.
That last point is the practical benefit people are gesturing at when they say "scripting". The file you are reading is the program that ran. There is no second artefact that can silently fall out of date.
4. Proof: Output First, Error Later
Now the behaviour that follows from having one moment instead of two. This script has a deliberate mistake on its last line:
puts "A"
puts "B"
puts "C"
oops_typoBefore running it, predict what happens. If your instinct comes from C or SystemVerilog, you may expect the whole file to be rejected and nothing to be printed.
tclsh late-error.tclA
B
C
invalid command name "oops_typo"
while executing
"oops_typo"
(file "late-error.tcl" line 4)Three lines of output, and then the failure. The first three commands ran, succeeded, and produced real output. The fourth was looked up, was not found, and stopped the script.
Nothing checked oops_typo in advance, because nothing read ahead. The interpreter worked through the file one command at a time and found the problem at the moment it mattered.
5. The Stronger Version: Code That Is Never Reached Is Never Checked
If an unknown command is only detected when reached, then an unknown command that is never reached is never detected. That sounds like a logical trick. It is literally how it behaves.
proc defines a new command, and the lines inside it do not run until something calls it. Here, nothing does:
proc never_called {} {
this_command_does_not_exist 42
}
puts "script finished without touching never_called"script finished without touching never_calledThe script exits successfully. this_command_does_not_exist is sitting in the file, plainly wrong, and Tcl has no complaint — because it never had reason to look that name up.
Call it, and the problem appears immediately:
proc now_called {} {
this_command_does_not_exist 42
}
puts "about to call it"
now_calledabout to call it
invalid command name "this_command_does_not_exist"
while executing
"this_command_does_not_exist 42"
(procedure "now_called" line 2)
invoked from within
"now_called"
(file "reached.tcl" line 5)Same file content, same mistake, different outcome — decided entirely by whether execution reached the line.
The engineering conclusion is direct: in Tcl, a code path you have not executed is a code path you have not checked. A script that works on the common case can be carrying a broken error handler, because the error handler has never run. That is the honest reason Tcl programs need to be exercised rather than merely read, and it is why Module 14 treats input validation as a habit rather than a nicety.
6. What "Not Compiled" Would Get Wrong
It is tempting to summarise all of this as "Tcl is interpreted, not compiled". That sentence is repeated often and is too crude to be useful.
What is accurate:
- There is no separate build step you run and no build artefact you manage. This is the real, practical difference, and §3 is it.
- There is no whole-program check before execution starts. §4 and §5 are it.
- Internally, Tcl does translate script and procedure bodies into an intermediate bytecode form as it evaluates them, and reuses that work on later evaluations. This is an implementation concern that affects performance, and you will meet one visible consequence of it in Module 3, where
expris introduced.
So Tcl is not "not compiled". It is a language with no build step, no build artefact, and no advance verification pass — which is a precise statement, and the one worth carrying forward.
7. Exercises
Exercise 1 — reproduce the late error. Create late-error.tcl from §4 and run it. Confirm you see three lines and then the error. Then move oops_typo to the first line and run again. How much output do you get now, and why?
Exercise 2 — the unreached mistake. Create unreached.tcl from §5 and confirm it exits without complaint. Now add never_called as a final line and run it again. You have just demonstrated, on your own machine, that reaching a line is what checks it.
Exercise 3 — argue the other side. Write two sentences on why "no advance check" is a disadvantage, and two on why a language used to drive other tools might accept that trade. There is a real trade-off here and it is worth being able to state both halves.
Exercise 4 — spot the imprecision. A colleague says "Tcl is slow because it is interpreted and never compiled." Using §6, identify which part of that sentence is wrong and restate it accurately. You are not expected to know anything about Tcl's actual performance — only to notice the claim that does not hold.
8. Summary
- Tcl is a programming language normally used in a scripting style. The label is not worth arguing about; one of its consequences is.
- There is no build step and no build artefact. The file you are reading is the program that ran.
- There is no whole-program check before execution. Lines one to three can print correct output before line four turns out not to be a command.
- A line that is never reached is never checked. A nonexistent command inside a procedure nobody calls produces no error and a clean exit.
- Therefore output is not proof of success. Exit status is the thing to check, which Chapter 1.9 covers.
- "Interpreted, not compiled" is too crude. Tcl byte-compiles bodies internally; what it lacks is a build step, a build artefact, and an advance verification pass.
The next chapter takes up something Chapter 1.1 §6 raised and left open: the same language runs both on its own and inside other programs, and knowing which situation you are in determines what you are allowed to type.
Where this fits
Part of the Tcl curriculum.
