Skip to content
VLSI Mentor

Tcl Part I · Module 7 · Dictionaries and Arrays

Reading and Writing Array Elements

The previous chapter established what an array is. This one gives you the working vocabulary: the two commands that load a whole array from a list and flatten it back out again, the one that removes things, and the ordinary variable syntax that handles everything in between. Two of these behave in ways people guess wrong about — array set adds to what is already there rather than replacing it, and array unset does two quite different jobs depending on how many arguments you give it. Both are easy once seen, and expensive when discovered by accident.

Foundation11 min readTclPart IArraysarray setarray get

Part I · Module 7 · Chapter 7.9 · Reading and Writing Array Elements

1. One element at a time

Elements are variables, so the ordinary commands work:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
set limits(retries) 3
set limits(timeout) 60

puts $limits(retries)

incr limits(retries)
puts $limits(retries)

append limits(note) "checked"
append limits(note) " twice"
puts $limits(note)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
3
4
checked twice

Nothing array-specific is happening. incr and append are the same commands from Chapter 3.9 and Chapter 5.10, operating on variables that happen to have parentheses in their names.

2. Loading a whole array at once

array set takes a flat list of alternating names and values:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
array set limits {retries 3 timeout 60 mode fast}

puts $limits(retries)
puts $limits(mode)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
3
fast

That list is exactly the shape of a dictionary — which is the bridge Chapter 7.12 is built on.

An odd number of elements is rejected:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
array set bad {a 1 b}
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
list must have an even number of elements

3. array set merges

Here is the one people guess wrong:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
array set m {a 1 b 2}
array set m {b 20 c 3}

foreach k [lsort [array names m]] {
    puts "m($k) = $m($k)"
}
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
m(a) = 1
m(b) = 20
m(c) = 3

a survived. The second array set did not replace the array — it set its two pairs into the array that was already there, overwriting b and adding c.

This is usually what you want, and it makes array set a natural way to apply defaults then override them:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
array set opt {retries 1 timeout 30 verbose 0}
array set opt {timeout 300}

puts "retries=$opt(retries) timeout=$opt(timeout) verbose=$opt(verbose)"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
retries=1 timeout=300 verbose=0

Defaults first, then the user's settings. Three lines, no loop.

4. Flattening it back out

array get is the inverse of array set:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
array set limits {retries 3 timeout 60 mode fast}
puts [array get limits]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
mode fast retries 3 timeout 60

A flat list of alternating names and values — the same shape you put in, and the same shape a dictionary is.

The order is not the order you wrote. It is whatever order the array's internal table happens to hold, and the language does not define it. Your interpreter may print those three pairs in a different order from this page, and that is not a bug. Chapter 7.10 deals with this properly; for now, never depend on it.

Both array get and array names take an optional glob pattern — the same language as dict keys in Chapter 7.4:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
array set p {max_fan 16 max_tran 0.4 mode fast}

puts [lsort [array names p max_*]]
puts [array get p max_*]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
max_fan max_tran
max_tran 0.4 max_fan 16

Note the lsort on the first line and not the second: sorting a list of names is easy, and sorting a flat pair list is not — which is the first sign that array get is for handing data onward, not for display.

5. Removing things

array unset does two jobs. With a pattern, it removes matching elements:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
array set p {max_fan 16 max_tran 0.4 mode fast}
array unset p max_*
puts [array names p]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
mode

With no pattern, it removes the entire array:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
array unset p
puts "exists: [array exists p]"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
exists: 0

A single element goes with ordinary unset:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
array set q {a 1 b 2}
unset q(a)
puts [array names q]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
b

6. Elements hold any string, including structures

An element is a variable, so it holds a string, so it can hold a list or a dictionary:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
set data(ports) [list clk rst din]
set data(cfg)   [dict create width 8 depth 16]

puts "ports: [llength $data(ports)] -> [lindex $data(ports) 1]"
puts "width: [dict get $data(cfg) width]"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
ports: 3 -> rst
width: 8

This is how arrays hold nested structure: the value nests, even though the array itself cannot. Updating one needs the usual get–modify–set, because the element is a value like any other:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
dict set data(cfg) width 32
puts [dict get $data(cfg) width]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
32

That works directly, because dict set takes a variable name and data(cfg) is a variable name.

7. A worked example

Reading options, applying defaults, reporting:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
proc show_opts {name} {
    upvar 1 $name opt
    foreach k [lsort [array names opt]] {
        puts [format "  %-10s %s" $k $opt($k)]
    }
}

# defaults, then overrides
array set opt {retries 1 timeout 30 verbose 0 mode slow}
array set opt {timeout 300 mode fast}

puts "settings ([array size opt]):"
show_opts opt

array unset opt verbose
puts "after dropping verbose ([array size opt]):"
show_opts opt
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
settings (4):
  mode       fast
  retries    1
  timeout    300
  verbose    0
after dropping verbose (3):
  mode       fast
  retries    1
  timeout    300

lsort appears in show_opts for the reason section 4 gave: without it, the output order is arbitrary. In a report, that is not acceptable, so sorting is not a nicety here.

8. Exercises

Exercise 1. After these two lines, what are all the elements and values?

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
array set a {x 1 y 2}
array set a {y 20 z 3}

Exercise 2. Write the two lines that completely replace an array's contents with {p 1 q 2}, discarding whatever was there.

Exercise 3. What is the error from array set a {1 2 3}, and why?

Exercise 4. Explain the difference between unset a(x), array unset a x* and array unset a.

Exercise 5. Store a dictionary in an array element, then change one of its keys, and print the result. Explain why dict set a(cfg) k v is allowed.

Exercise 6. Write defaults — a procedure that takes an array name and a flat list of default pairs, and sets only the elements that are not already present.

Answers

1. x=1, y=20, z=3. array set merges: x survives, y is overwritten, z is added.

2.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
array unset a
array set a {p 1 q 2}

3. list must have an even number of elements. array set needs alternating names and values, and three items cannot pair up.

4. unset a(x) removes exactly the element x. array unset a x* removes every element whose name matches the pattern. array unset a removes the whole array, after which array exists a is 0.

5.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
set a(cfg) [dict create width 8]
dict set a(cfg) width 32
puts $a(cfg)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
width 32

dict set needs a variable name, and a(cfg) is the name of a real variable — the point of Chapter 7.8 §2. Nothing special is needed.

6.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
proc defaults {name pairs} {
    upvar 1 $name a
    foreach {k v} $pairs {
        if {![info exists a($k)]} { set a($k) $v }
    }
}

array set opt {timeout 300}
defaults opt {retries 1 timeout 30 verbose 0}
foreach k [lsort [array names opt]] { puts "$k = $opt($k)" }
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
retries = 1
timeout = 300
verbose = 0

timeout kept the value it already had. Note this is the opposite order from section 3's idiom — here the defaults are applied after, so they must not overwrite.

9. Remember

  • Elements are variables. set, incr, append and unset all work on them directly.
  • array set name list loads a whole array from alternating names and values; an odd count is list must have an even number of elements.
  • array set merges — it does not replace. To replace, array unset first.
  • That merge makes defaults easy: defaults first, overrides second.
  • array get name flattens to a dictionary-shaped list, in an order the language does not define. Never rely on it.
  • Both array get and array names take a glob pattern, same language as dict keys.
  • array unset a pat removes matching elements; array unset a removes everything. One argument apart.
  • array set name {} is the only way to make an empty array.
  • An element can hold a list or a dictionary, and dict set a(cfg) k v works because a(cfg) is a variable name.

Where this fits

Part of the Tcl curriculum.