A '''gotcha''' is an ''unexpected side effect, behavior, consequence, requirement, etc.'' [Larry Smith] I was expecting a new control construct of some sort. gotcha { ... } now {...} ** Description ** As with any language, the syntax and semantics of [Tcl] can catch a programmer off guard. This page is enumerates constructs and behaviours that can be considered as '''gotcha'''s, and is somewhat arranged by prominence and severity. ** Gotchas ** *** [Tcl and octal numbers%|%The Octal Bug%|%] *** See [Tcl and octal numbers] *** `[set]` and namespaces *** [Twylite] 2012-12-12: Setting a variable in a '''namespace eval''' can clobber a global variable. See [Dangers of creative writing]. ====== set foo 10 namespace eval bar { set foo 20 ; set bar 30 } puts $foo ;# puts: 20 puts $bar ;# error: can't read "bar": no such variable ====== *** Assuming that a value is a [dict%|%dictionary] *** In the following example the fact that `$dict` is not a dictionary does not trigger an error: ====== set dict hello dict exists $dict Bob ;# -> 0 ====== *** Assuming that a value is a [list] *** Another Tcl '''gotcha''' is to hand arbitrary strings, read from the user or a file/command, directly into a list operation without first ensuring that the contents is, in actuality, a [list]. [DKF]: The best way to deal with such user input, where users aren't expecting to write a Tcl list in the first place, is to use a sanitizing command to convert the input into a proper list. Examples of sanitization commands can include [split], [splitx] and (my favorite) this: ====== set elements [regexp -all -inline {\S+} $line] ====== *** Assuming that a variable is an [array] *** Using `[array unset]` on a variable that isn't array does nothing, and does not triggeer an error: ====== set array 5 array unset array set array ;# -> 5 ====== *** [lsearch] default matching style is `-glob` *** Forgetting to use `-exact` when that's what is intended can lead to surprises. *** `switch` and its Arguments *** [RS] One possible gotcha is `[switch]` -- always use `--` before the switch variable, since if the value of the switch variable starts with `-`, you'll get a syntax error. [AMG]: This isn't required by Tcl 8.5 onward. *** Delimiting Options from Arguments *** [KPV] Also, [comment]s within [switch], while possible, are tricky. [RS] 2010-05-10: A similar gotcha is in the '''[text] search''' subcommand - although the misunderstanding could be avoided by counting non-optional arguments from the end, ====== set whatever -this $t search $whatever 1.0 ====== raises an error that `-this` is an undefined switch. For robustness, use ====== $t search -- $whatever 1.0 ====== if the slightest possibility exists that $whatever might start with a dash. [PYK] 2017-05-19: [scripted lists] makes comments within a switch possible, but it needs to move into the Tcl implementation level to be performant. *** Interpretations by `[expr]` *** [RS] 2010-02-24: Yet another gotcha we ran into last night: Consider a function ====== proc f x { if {$x == 00000000} { puts "$x is NULL" } } ====== which reported: ======none 0E123456 is NULL ====== How so? Bug? No -- feature. With the `[==]` comparison operator, the operands are tried to match as integers, floats, or then as strings. And `$x` in this case, though meant as a pointer in hex, could be parsed as float - with the numeric value of 0, which is numerically equivalent to 00000000. The solution of course was to use the `[eq]` operator instead. [AMG]: Another issue with `[expr]` interpreting stuff happens when said stuff was already interpreted by Tcl. This creates performance, security, and correctness problems. Always [brace your expr-essions]! Another example: ====== expr {{} < 0} ;# -> 1 expr {{} > 0} ;# -> 0 expr {{} == 0} ;# -> 0 ====== For the `<` and `>` operators, `{}` is interpreted as an integer, `0`. For the `==` operator, 0 is interpreted as a string. because *** `[string is]` and the empty string *** `[string is]` always returns 1 for the [empty string]. To avoid this, use `-strict` *** Confirming that a value is an integer decimal notation *** The `[string is]` commands accept all the numeric notations that `[expr]` does (see [Tcl and octal numbers%|%The Octabug], so they aren't up to the job by themselves. Here is one way to do it: ====== set mynumber 0x11 expr {[string is entier -strict $mynumber] && [scan $mynumber %d mynumber] > 0} ====== *** Partial sub-command resolution in [namespace] [namespace ensemble%|%ensembles] *** ======none namespace eval table { namespace export * namespace ensemble create } proc {table::spoon fork} x { return $x } ====== Even though there is no `spoon`, there is: ======none % puts [table spoon huh?] huh? ====== To change this behavior: ====== namespace ensemble configure table -prefixes no ====== ** Nested `[vwait]` ** See `[http://wiki.tcl.tk/1302#pagetoc914efb06%|%Avoiding Conflicting vwait's] on the [vwait] page` ** Starving Queues with `[after]` ** See `[http://wiki.tcl.tk/808#pagetoc0f64563c%|%after x after idle] on the [after] page` ** See Also ** [Dangerous constructs]: <> Glossary