Skip to content
VLSI Mentor

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:

Azvya Education Pvt. Ltd.VLSI Mentor
same.tcl
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}]"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
a equals b? 1
b equals c? 1
lengths:     2 2 2
all plus 1:  13 13 13

All 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:

Azvya Education Pvt. Ltd.VLSI Mentor
three-readings.tcl
set v "1 2 3"

puts "string length -> [string length $v]"
puts "llength       -> [llength $v]"
puts "lindex 0      -> [lindex $v 0]"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
string length -> 5
llength       -> 3
lindex 0      -> 1

Three answers from one value, and none of them is wrong.

  • string length read it as text. Five characters: 1, space, 2, space, 3.
  • llength read it as a list. Three elements.
  • lindex read it as a list and took the first element.

The value did not change between the lines. The command decided what it meant.

Two parallel left-to-right flows. The same value twelve is read by string length, which answers two because it counts characters, and by expr plus one, which answers thirteen because it reads the text as a number.The value12string lengthreads it as textAnswer: 2two charactersThe same value12expr + 1reads it as a numberAnswer: 13arithmetic12
Figure 1 — one value, two commands, two different answers. The value is the same text in both rows. What differs is the command reading it: string length counts characters, while expr reads the same text as a number. Neither reading is more correct than the other, and the value itself carries no type that would settle it.

5. The Same Value, Both Ways, in One Script

Worth seeing in one place:

Azvya Education Pvt. Ltd.VLSI Mentor
both-ways.tcl
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"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
as text:   length is 2, first character is 1
as number: plus one is 13, doubled is 24
as text again: still 2 characters

Reading 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.

Azvya Education Pvt. Ltd.VLSI Mentor
composing.tcl
set reading "42"

puts "doubled:  [expr {$reading * 2}]"
puts "padded:   [format %05d $reading]"
puts "as text:  [string repeat $reading 3]"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
doubled:  84
padded:   00042
as text:  424242

The 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:

Azvya Education Pvt. Ltd.VLSI Mentor
no-type.tcl
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"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
is x a number or text? both, depending on who asks
  as a number: 42
  as text:     2 characters

Tcl 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:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
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.