set docu(constrain) {[Richard Suchenwirth] - Here's an application of write traces to constrain a variable's value to either a range (numeric or string prefix, joined with two dots) or a list of permitted values, that work on scalars, arrays or array elements. Examples: constrain x 0..1023 constrain y {yes no maybe} constrain z(mode) A..Z If a constraint is violated, an error is raised with a descriptive message: can't set "y": value 'yesSir' outside constraint 'yes no maybe' As usual with traces, constraints are deleted if the variable is unset. If you still want to set an out-of-constraint value, just catch the assignment: catch {set y "definitely"} This is because write traces fire after the assignment, so the "bad" value is there anyway. Numeric constraints don't distinguish between int and double values; string prefixes are just that, so "foo" is inside the range "a..z" even if it's not a single character. You can introspect the constraints you have set by calling constrain name which returns the active constraint in the same format, or an empty string if the variable is not constrained. Also, you can remove a constraint by overriding it with an empty string: constrain name "" } set docu(comment1) {[KPV] -- I like the idea, and like to offer a suggestion. How about an optional argument which the value the variable should take if it is out of range. Sometimes I think that throwing an error is too harsh, and catching that error still leaves that bad value in place. } proc constrain {var {cond -}} { if {$cond=="-"} { set trace [lindex [lindex [uplevel 1 trace vinfo $var] end] end] return [join [lrange $trace 1 end] ..] } foreach i [uplevel 1 trace vinfo $var] { if [regexp constrain $i] {uplevel 1 trace vdelete $var $i} } if {$cond==""} return if [regexp {(.+)[.][.](.+)} $cond -> from to] { set trace [list constrainRange $from $to] } else { set trace [list constrainList $cond] } uplevel 1 trace var $var w [list $trace] } proc constrainRange {from to _var el op} { set name $_var[expr {$el!=""? "($el)": ""}] upvar 1 $name var if {$var<$from || $var>$to} { return -code error "value $var outside constraint $from..$to" } } proc constrainList {list _var el op} { set name $_var[expr {$el!=""? "($el)": ""}] upvar 1 $name var if {[lsearch $list $var]<0} { return -code error "value '$var' outside constraint '$list'" } } See also [constants] for traces used to prevent a variable value from being changed, and [type checking]. ---- [Category Concept] | [Arts and crafts of Tcl-Tk programming]