Dict Key Path Commands

VI 2015-10-23 : I have deeply nested structures built with dicts, and it makes for very descriptive code. I have often been inconvenienced by some dict commands only applying to the first level of keys. Examples are dict create, dict append, dict lappend, dict incr, dict update. So I implemented one of these commands (incr). The p in dict-pincr stands for path.


e.g. I would like this script:

dict set a b c d m wi 0
dict-pincr a {b c d m wi}
puts $a

to print:

b {c {d {m {wi 1}}}}

This works. but could be improved. I used the empty variable name {} to reduce the chance of a conflict, but I think this should be possible without upvar.

proc dict-pincr {dictname keypath} {
    set keylen [llength $keypath]
    if {$keylen < 1} {
        error "Need at least one key name"
    } elseif {$keylen == 1} {
        uplevel 1 [list dict incr $dictname [lindex $keypath 0]]
    } else {
        upvar $dictname {}
        dict with {} {
            dict-pincr [lindex $keypath 0] [lrange $keypath 1 end]
        }
        return [set {}]
    }
}

lappend:

proc dict-plappend {dictname keypath args} {
    set keylen [llength $keypath]
    if {$keylen < 1} {
        error "Need at least one key name"
    } elseif {$keylen == 1} {
        uplevel 1 [list dict lappend $dictname [lindex $keypath 0] {*}$args]
    } else {
        upvar $dictname {}
        dict with {} {
            dict-plappend [lindex $keypath 0] [lrange $keypath 1 end] {*}$args
        }
        return [set {}]
    }
}

dict set a b c d m wi 0
dict-plappend a {b c d m wi} 1 2 3 4
puts $a

gives

b {c {d {m {wi {0 1 2 3 4}}}}}