Tcl Part I · Module 3 · Values, Variables, and Expressions
Everything Is a String
This is the most repeated sentence about Tcl, and repeating it without qualification is how people end up with the wrong model. The useful version is this: every Tcl value carries text, and what that text means is decided by the command that reads it. A variable is not declared as a number or a string, because values do not carry types around with them. This chapter shows one value being read three different ways by three different commands, which is something the slogan on its own cannot explain — and then states accurately what modern Tcl actually does underneath, so you do not come away thinking Tcl is slow.
Foundation13 min readTclPart IValuesTypesMental Model
Part I · Module 3 · Chapter 3.1 · Everything Is a String
1. The Question This Answers
In C you write int count = 0; and the variable is an integer forever. In Python a value knows its own type — type(12) says int, type("12") says str, and the two behave differently.
Tcl does neither. There is no declaration, and 12 and "12" are not two different things.
If you arrive expecting types, you will keep asking "what type is this variable?" — a question Tcl has no answer to. This chapter replaces that question with one that does have an answer.
2. The Rule
Every Tcl value carries text. What that text means is decided by the command that reads it.
That is the whole model. Hold on to the second half, because it is the part the slogan leaves out and the part that actually predicts behaviour.
3. Same Value, Written Three Ways
Module 2 taught that quotes and braces are grouping instructions that do not survive into the value. So these three lines store the same thing:
set a 12
set b "12"
set c {12}
puts "a equals b? [string equal $a $b]"
puts "b equals c? [string equal $b $c]"
puts "lengths: [string length $a] [string length $b] [string length $c]"
puts "all plus 1: [expr {$a + 1}] [expr {$b + 1}] [expr {$c + 1}]"a equals b? 1
b equals c? 1
lengths: 2 2 2
all plus 1: 13 13 13All three are identical. There is no "string 12" and "number 12" to tell apart — quoting changed how the word was grouped while the line was read, and then it was gone.
4. One Value, Three Readings
Now the demonstration that the slogan cannot explain. Here is a single value, read by three different commands:
set v "1 2 3"
puts "string length -> [string length $v]"
puts "llength -> [llength $v]"
puts "lindex 0 -> [lindex $v 0]"string length -> 5
llength -> 3
lindex 0 -> 1Three answers from one value, and none of them is wrong.
string lengthread it as text. Five characters:1, space,2, space,3.llengthread it as a list. Three elements.lindexread it as a list and took the first element.
The value did not change between the lines. The command decided what it meant.
5. The Same Value, Both Ways, in One Script
Worth seeing in one place:
set n 12
puts "as text: length is [string length $n], first character is [string index $n 0]"
puts "as number: plus one is [expr {$n + 1}], doubled is [expr {$n * 2}]"
puts "as text again: still [string length $n] characters"as text: length is 2, first character is 1
as number: plus one is 13, doubled is 24
as text again: still 2 charactersReading it as a number did not convert it, consume it, or change it. The next line read it as text again and got the same answer as before.
6. What This Buys You
This design is why Tcl commands compose so freely. A command that returns text can feed any command that accepts text — and since every value is text, that means any command at all.
set reading "42"
puts "doubled: [expr {$reading * 2}]"
puts "padded: [format %05d $reading]"
puts "as text: [string repeat $reading 3]"doubled: 84
padded: 00042
as text: 424242The same value went to an arithmetic command, a formatting command, and a text command. No conversion was written, and none was needed.
In a language with strict types you would be converting at each boundary. Here the boundary does not exist.
7. What "Everything Is a String" Gets Wrong
Taken literally, the slogan suggests Tcl stores everything as text and re-parses it constantly — which would make it very slow.
That is not what happens. Modern Tcl keeps an efficient internal representation alongside the text. When you use a value as an integer, Tcl holds an integer internally and reuses it next time. When you use it as a list, it holds a list. The text representation is always available, which is what makes the model work, but it is not necessarily what Tcl is working with at the time.
Two consequences worth having:
- Tcl is not doing text parsing on every arithmetic operation. Using a value as a number repeatedly is cheap.
- You never have to think about this. It is an optimisation underneath a model that behaves exactly as described in §2.
So the accurate sentence is: every Tcl value has a string representation, and the command that reads it decides what it means. That is the version to carry.
8. There Is No Type to Ask For
A question with no answer:
set x 42
puts "is x a number or text? both, depending on who asks"
puts " as a number: [expr {$x + 0}]"
puts " as text: [string length $x] characters"is x a number or text? both, depending on who asks
as a number: 42
as text: 2 charactersTcl has no type command because there is nothing for it to report. What you can ask is whether a value would work as a number — which is Chapter 3.5, and is a different and more useful question.
9. Common Mistakes
Looking for a type declaration. There is none. Variables hold values; values carry text.
Thinking quoting creates a type. "12" and 12 are identical. Module 2 §2.7 showed the quotes do not survive.
Expecting a value to "be" a list. A value can be read as a list if its text follows list rules. llength on "1 2 3" works; on "hello" it returns 1. Module 6 covers this properly.
Assuming Tcl is slow because of this. §7.
Expecting a command to reject a value for having the wrong type. Commands reject values they cannot read, which is not the same thing. expr rejects abc because it is not numeric text, not because it has a type.
10. Exercises
Exercise 1 — prove the identity. Write a script showing that 7, "7" and {7} are the same value, using string equal and one arithmetic operation.
Exercise 2 — three readings. Take the value "10 20 30" and produce three different answers from it using three different commands. Say in one sentence what each command decided the value meant.
Exercise 3 — predict the lengths. Before running, write down what each line prints:
set a 100
set b "100"
set c "1 0 0"
puts [string length $a]
puts [string length $c]
puts [llength $c]
puts [llength $a]The last one is the interesting case. Explain it.
Exercise 4 — compose freely. Set a variable to 7, then in one script: double it with expr, pad it to three digits with format %03d, and repeat it four times with string repeat. Confirm no conversion step was needed anywhere.
Exercise 5 — state the rule. Write the accurate version of "everything is a string" in one sentence, without using the word "string". Compare it with §2.
11. Remember
- Every Tcl value carries text. There are no type declarations and no types attached to values.
- What a value means is decided by the command that reads it. That is the half the slogan omits, and the half that predicts behaviour.
12,"12"and{12}are the same value. Quoting is grouping, and it does not survive into the value.- One value can be read several ways — as text, as a number, as a list — and reading it one way does not change it.
- This is why Tcl commands compose without conversion steps.
- Modern Tcl keeps an efficient internal representation too, so this model does not mean constant re-parsing.
- There is no type to ask for. Ask instead whether a value will work as a number — Chapter 3.5.
Next: the command that puts values into variables, and the small surprise in how it reads them back.
Where this fits
Part of the Tcl curriculum.
