Skip to content
VLSI Mentor

Tcl Part I · Module 7 · Dictionaries and Arrays

Dictionaries: dict set and dict get

This is the chapter that changes how you store things. A dictionary pairs each value with a name you choose, so a record stops being a sequence you have to count through and becomes something you read. The commands are small and there are only two you need to start. One of them, though, takes a variable name while the other takes a value — and when you mix those up, Tcl does not stop you, does not warn you, and quietly puts your data somewhere you will never look. That trap is in here, demonstrated, because finding it yourself at midnight is worse.

Foundation11 min readTclPart IDictionariesdict setdict get

Part I · Module 7 · Chapter 7.2 · Dictionaries: dict set and dict get

1. Two ways to make one

dict create takes alternating keys and values and returns a dictionary:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
set cfg [dict create mode fast runs 3]
puts $cfg
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
mode fast runs 3

dict set builds one a pair at a time, into a variable:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
dict set cfg2 mode fast
dict set cfg2 runs 3
puts $cfg2
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
mode fast runs 3

Both produce the same value. Note that cfg2 did not have to exist first — dict set created it. That is convenient and it is also how a typo becomes a new dictionary instead of an error, which is worth remembering.

2. Reading a value back

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
set cfg [dict create mode fast runs 3 width 8]
puts [dict get $cfg mode]
puts [dict get $cfg width]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
fast
8

dict get takes the dictionary and the key, and returns the value. That is the whole command.

3. Updating, and where the key ends up

Setting a key that already exists replaces its value:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
set cfg [dict create mode fast runs 3]
dict set cfg runs 10
puts $cfg
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
mode fast runs 10

Setting a key that does not exist appends it at the end:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
dict set cfg width 8
puts $cfg
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
mode fast runs 10 width 8

Dictionaries remember insertion order. That is a real guarantee you can rely on, and it is one of the places where dictionaries and arrays differ sharply — Chapter 7.10 shows an array doing the opposite.

Order survives rewriting, too. An updated key stays where it was rather than moving to the end:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
set d [dict create]
foreach k {zebra apple mango} { dict set d $k 1 }
puts [dict keys $d]

dict set d zebra 99
puts [dict keys $d]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
zebra apple mango
zebra apple mango

zebra kept its position. Only genuinely new keys go on the end.

4. When the key is not there

dict get on a missing key is an error, not an empty string:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
set cfg [dict create mode fast]
puts [dict get $cfg runs]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
key "runs" not known in dictionary

This is deliberate, and it is different from what Chapter 6.4 taught about lindex, which returns an empty string for an out-of-range index. A dictionary key is something you named on purpose, so asking for one that is not there is treated as a mistake worth stopping for.

Handling that properly is the whole of Chapter 7.3.

5. Keys and values can be anything

A key is just a string, so it can contain spaces, punctuation, or digits — as long as you group it so that it stays one word:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
set d [dict create]
dict set d "max fanout" 16
dict set d 42 answer
puts $d
puts [dict get $d "max fanout"]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
{max fanout} 16 42 answer
16

Look at the stored form: {max fanout} came back braced. That is the same automatic quoting Chapter 6.2 showed for list — a dictionary is a value with list structure, so it quotes whatever it must to keep the structure readable.

Values work the same way:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
dict set d note "two words here"
puts $d
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
{max fanout} 16 42 answer note {two words here}

6. A dictionary is a value — with all that implies

Section 4 of Chapter 7.1 proved a dict is literally its own flat text. Two practical consequences follow immediately.

First, you can print one, store one in a file, and read it straight back:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
set cfg [dict create mode fast runs 3]
set line $cfg
puts [dict get $line mode]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
fast

No serialisation step. The text form is the dictionary.

Second, an odd number of words is not a dictionary, and Tcl says so the moment you try to use it as one:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
puts [dict get "a 1 b" a]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
missing value to go with key

That is the dictionary equivalent of unmatched open brace in list from Chapter 6.3: the text is fine as text, and it does not satisfy the rules this command reads by.

7. The asymmetry that fails silently

This is the one to internalise.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
dict set cfg mode fast     ;# takes a VARIABLE NAME — cfg
dict get $cfg mode         ;# takes a VALUE        — $cfg

dict set modifies a variable, so it needs the name, exactly like lappend and lset in Chapter 6.6 and Chapter 6.8. dict get just reads a value, so it takes the value, exactly like llength and lindex.

Now watch what happens when you write $cfg where cfg belongs:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
set cfg [dict create mode fast runs 3]
dict set $cfg width 8

puts "cfg is still: $cfg"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
cfg is still: mode fast runs 3

No error. The update vanished. Where did it go?

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
puts [set {mode fast runs 3}]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
width 8

Tcl did exactly what you asked. $cfg substituted to the text mode fast runs 3, dict set took that text as a variable name, and created a variable with that name holding a one-pair dictionary. Your actual configuration was never touched.

8. A worked example

Collect a few settings, then report on them:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
set run [dict create]
dict set run name  smoke
dict set run width 8
dict set run cycles 2000
dict set run mode  fast

puts "name   : [dict get $run name]"
puts "width  : [dict get $run width]"
puts "cycles : [dict get $run cycles]"
puts "stored : $run"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
name   : smoke
width  : 8
cycles : 2000
stored : name smoke width 8 cycles 2000 mode fast

Then change one thing and pass the whole record to a procedure:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
dict set run cycles 5000

proc describe {r} {
    return "[dict get $r name]: [dict get $r cycles] cycles at width [dict get $r width]"
}

puts [describe $run]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
smoke: 5000 cycles at width 8

The procedure received the entire record as one argument. That is the payoff from Chapter 7.1, in use.

9. Exercises

Exercise 1. What does this print, and why is it not an error?

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
dict set brandnew key value
puts $brandnew

Exercise 2. Build a dictionary describing a port with keys name, dir and width, then print a single line like clk is an in port, 1 bit(s).

Exercise 3. Predict the output before running it:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
set d [dict create a 1 b 2]
dict set d a 99
dict set d c 3
puts [dict keys $d]

Exercise 4. Explain, in one sentence each, why dict set takes cfg and dict get takes $cfg.

Exercise 5. The following runs without error and does not do what it looks like. Say what it actually does.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
set cfg [dict create a 1]
dict set $cfg b 2

Exercise 6. Write a procedure bump that takes a dictionary and a key, returns a new dictionary with that key's value increased by one, and leaves the caller's dictionary unchanged. Prove it is unchanged.

Answers

1. It prints key value. dict set creates the variable if it does not exist, so there is nothing to complain about — which is also why a mistyped variable name silently becomes a brand-new dictionary.

2.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
set p [dict create name clk dir in width 1]
puts "[dict get $p name] is an [dict get $p dir] port, [dict get $p width] bit(s)"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
clk is an in port, 1 bit(s)

3. a b c. Rewriting a leaves it in place; only the new key c goes on the end.

4. dict set modifies the variable, so it needs the name in order to find it. dict get only reads, so it needs nothing but the value itself.

5. $cfg becomes the text a 1, so dict set creates a variable named a 1 holding the dictionary b 2. cfg is unchanged, and no error is reported.

6.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
proc bump {d key} {
    dict set d $key [expr {[dict get $d $key] + 1}]
    return $d
}

set counts [dict create hits 4]
set newer [bump $counts hits]
puts "returned: $newer"
puts "original: $counts"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
returned: hits 5
original: hits 4

The procedure's d is its own copy, so modifying it cannot affect the caller's variable — the same value semantics Chapter 6.6 relied on.

10. Remember

  • dict create k v ... returns a dictionary; dict set name k v builds one into a variable and creates that variable if needed.
  • dict get $d key returns the value, and errors with key "..." not known in dictionary if there is none.
  • That error is deliberate — unlike lindex, which returns an empty string out of range.
  • Dictionaries preserve insertion order, and rewriting a key keeps it in place.
  • Keys and values are just strings, automatically quoted when they contain spaces. Keep keys boring anyway.
  • An odd number of words is not a dictionary — missing value to go with key.
  • dict set takes a name; dict get takes a value. Writing dict set $cfg ... creates a variable named after your data and silently loses the update.
  • Modifying commands take the bare name; reading commands take $name.

Where this fits

Part of the Tcl curriculum.