Comments 10
Хм. У меня никогда переменные типа $menu-settings не работали. Приходится заворачивать ${menu-settings}. Вот и сейчас выдает ошибку.
Ну и:
key "menuBar" not known in dictionary
    while executing
"dict get ${user-settings} 0 "menuBar""
    (procedure "assemble-my-menu" line 6)
    invoked from within
"assemble-my-menu"
Спасибо! Сейчас должно работать. Совсем забыл про особенность tcl, начал по привычке имена задавать как на lisp. Сейчас переделал весь код под рабочий.
Аааа, какой кошмар. Автор, пожалуйста, идите и прочитайте про словари, прежде чем писать о них статьи.
Вместо
dict set nonUserSettings 0 title "myPrograms"
dict set nonUserSettings 0 minWidth 800
dict set nonUserSettings 0 minHeight 600
dict set nonUserSettings 0 resizableX 1
dict set nonUserSettings 0 resizableY 1

надо было бы написать гораздо более читаемое
set nonUserSettings {
    0 {
        title "myPrograms"
        minWidth 800
        minHeight 600
        resizableX 1
        resizableY 1
    }
}

или, если Вам нужно только дополнить уже имеющийся словарь:
dict set nonUserSettings 0 {
    title "myPrograms"
    minWidth 800
    minHeight 600
    resizableX 1
    resizableY 1
}

Ну и, наконец, почему 0?
0 потому, что в математике принято начинать исчисления итератора с 0 :). А так — описывал зачем задавать ID. Форму записи знаю, но по моему она более читаема и понятна изначально (когда только учишься работать со словарями), чем приведенное Вами (хотя может быть это просто для меня, не спорю).
Нерелеватно. Зачем Вы помещаете числа в ключи словаря? И нет, она менее читаема и понятна, потому что Вы упускаете главное в сути словарей. То, что они могут интерпретироваться как списки или строки. По сути, словарь можно рассматривать как строку с сопутствующим ей индексом. Более того, для этого словари и создавались, чтобы иметь общее представление со списками и обычными строками, потому как до этого были ассоциативные массивы (array), которые таким свойством не обладали, а потому приходилось к ним применять всякую злую магию.

В общем. Прежде чем писать о чём-то, в этом чём-то надо сперва разобраться. Вы не разобрались. Незачёт! :)
Более того, в итоге у Вас получился совершенно нечитаемый монстр, который выглядит хуже, чем если бы Вы его не писали, а сделали по-обычному. Чудеса, да, но тем не менее.
Посмотрите для примера, как всё то же самое можно сделать красиво, изящно и наглядно:
#!/usr/bin/env wish

package require Tcl 8.5
package require Tk

set windowparams {
    title myPrograms
    minsize {800 600}
    resizable {1 1}
}

set userconfig {
    menubar yes
}

set menu {
    Connection {
        "Log in" {
            -command login
        }
        "Log out" {
            -command logout
        }
        Exit {
            -command exit
        }
    }
    Help {
        About {
            -command about
        }
        Help {
            -command help
        }
    }
    -name menu
}

proc setup-window {w params} {
    wm title $w [dict get $params title]
    wm resizable $w {*}[dict get $params resizable]
    wm minsize $w {*}[dict get $params minsize]
}

proc build-menu {menu w args} {
    set label ""
    dict with args {
        set options [dict filter $menu key -*]
        if {[dict exists $options -command]} {
            $w add command -command [dict get $options -command] -label $label
        } else {
            if {[dict exists $options -name]} {
                set name [dict get $options -name]
            }
            set m [menu $w.$name]
            foreach {k v} $menu {
                if {![string match -* $k]} {
                    build-menu $v $m label $k name [incr i]
                }
            }
            if {[llength $args]} {
                $w add cascade -menu $m -label $label
            } else {
                $w configure -menu $m
            }
            return $m
        }
    }
}

setup-window . $windowparams
if {[dict get $userconfig menubar]} {
    build-menu $menu .
}


Да, опцию tearoff я выкинул, потому как, как мне кажется, это если кому-то настраивать и захочется, то глобально по всей системе, а для этого есть .Xdefaults.
Хотя и «Everything is a string», но использовать строки вместо dict/list — не самый хороший тон. Это намного запутывает разбор исходника. Смотря на Ваш код, например, непонятно как будут использоваться переменные windowparams/userconfig/menu: как строки? как dict? или выбирать нужные параметры по lsearch? или завернете в array через array set?

Таки правильнее списки делать через [list], строки через ""/{}, словари через [dict create]. Вот так более разборчивей:
set nonUserSettings \
[dict create 0 [dict create\
title «myPrograms» \
minWidth 800 \
minHeight 600 \
resizableX 1 \
resizableY 1]]
Вы неправы. Во-первых, через {} читабельнее. Во-вторых, т.к. в Tcl нет типов, каждая строка может интерпретироваться в зависимости от контекста. В-третьих, создание внутреннего представления list или dict быстрое, причём, что занимательно, гораздо эффективнее это сделать сразу, чем так, как Вы написали. Почему — читайте исходники. Списки надо делать через [list] тогда, когда у нас есть неконстантные в них значения, т.к. [list] автомагически сделает им правильное строковое представление. Делать же словари через [dict create] нужно вообще только в исключительных случаях.

Ваш пример с [dict create] и бэкслешами — это вообще нечитаемый и как раз-таки запутанный ужас.

В общем, почитайте хороший код на Tcl, сходите на http://wiki.tcl.tk/ и поучитесь у других.
Only those users with full accounts are able to leave comments. Log in, please.