The following is a few extensions to the dict command which I have found useful. (The proc-ensemble command is the one shown on my fredderic's gems page.) Of the lot shown here, the two get variants are by far the most useful.
If key exists within the dictionary, then store the value in varName and return true. Otherwise, returns false and leaves the variable unchanged.
If key exists within the dictionary, then return it as usual. Otherwise, return the supplied default value.
Sets a new value in the dictionary, but returns any existing value in the manner of dict get? as well.
Sets a new value in the dictionary, but only if no value for that key already exists. (Not particularly useful, but it's had its moments.)
Unsets a key from the dictionary, but returns any existing value in the manner of dict get? as well.
Mostly for symmetry, this one simply doesn't error if the key does not exist.
Intended primarily for dictionary keys containing lists of flags, this command won't append the given value to a key which already contains it.
Sets the specified key / value pair over each of the sub-keys listed in itemList.
Merge several dictionaries, inserting an extra level of nesting to distinguish the values from each dictionary.
proc-ensemble ::dict { get? {args} { # dict::get to variable and return boolean if { [llength $args] < 3 } { error-args "dict get? dictionary key ?...? varName" } ::set varName [lindex $args end] ::set args [lrange $args 0 end-1] if { [llength [lindex $args 0]] % 2 == 1 } { return -level 1 -code error \ "missing value to go with key" } if { [dict exists {*}$args] } { uplevel 1 [list ::set $varName [dict get {*}$args]] return 1 } return 0 } get! {args} { # dict::get with default return value if { [llength $args] < 3 } { error-args "dict get! dictionary key ?...? default" } ::set default [lindex $args end] ::set args [lrange $args 0 end-1] if { [llength [lindex $args 0]] % 2 == 1 } { return -level 1 -code error \ "missing value to go with key" } if { [dict exists {*}$args] } { return [dict get {*}$args] } else { return $default } } set? {args} { # dict::set but return previous value if { [llength $args] < 4 } { error-args "dict set? varName key ?...? value varName" } upvar 1 [lindex $args 0] dict [lindex $args end] var ::set path [lrange $args 1 end-2] ::set valu [lindex $args end-1] if { [::info exists dict] && [dict exists $dict {*}$path] } { ::set var [dict get $dict {*}$path] ::set rc 1 } else { ::set rc 0 } dict ::set dict {*}$path $valu return $rc } set! {args} { # dict::set but only if element doesn't exist if { [llength $args] < 3 } { error-args "dict set! varName key ?...? value" } upvar 1 [lindex $args 0] var ::set args [lrange $args 1 end] if { ! [::info exists var] || ! [dict exists $var {*}[lrange $args 0 end-1]] } { dict set var {*}$args } return $var } unset? {args} { # dict::unset but returns boolean and old value if { [llength $args] < 3 } { error-args "dict unset? varName key ?...? retVar" } upvar 1 [lindex $args 0] var [lindex $args end] ret ::set args [lrange $args 1 end-1] if { [::info exists var] && [dict exists $var {*}$args] } { ::set ret [dict get $var {*}$args] dict unset var {*}$args return 1 } return 0 } unset! {args} { # dict::unset but doesn't throw error if { [llength $args] < 2 } { error-args "dict unset! varName key ?...?" } upvar 1 [lindex $args 0] var ::set args [lrange $args 1 end] if { ! [::info exists var] || ! [dict exists $var {*}$args] } return return [dict unset var {*}$args] } lappend! {args} { # dict::append but only if list element doesn't exist if { [llength $args] < 3 } { error-args "dict lappend! varName key ?...? value" } upvar 1 [lindex $args 0] var ::set value [lindex $args end] ::set args [lrange $args 1 end-1] if { [::info exists var] && [dict exists $var {*}$args] } { ::set list [dict get $var {*}$args] if { $value in $list } {return $var} lappend list $value } else { ::set list [list $value] } return [dict set var {*}$args $list] } multiset {args} { # dict::set that sets the same key/value over multiple sub-keys if { [llength $args] < 4 } { error-args "dict multiset dictionary ?key ...? itemList key value" } ::set keys [lassign [lrange $args 0 end-3] dictionary] lassign [lrange $args end-2 end] items key value # now process the multiset ::set dict [dict get $dictionary {*}$keys] foreach item $items { dict set dict $item $key $value } if { [llength $keys] == 0 } {return $dict} return [dict set dictionary {*}$keys $dict] } zip {args} { # dict::merge that adds a level inbetween if { [llength $args] % 2 == 1 } { error-args "dict zip ?key dictionary? ..." } ::set dict [list] foreach {key items} $args { dict for {name item} $items { dict set dict $name $key $item } } return $dict } }