An '''idiom''' is a sort of language hack in which the real meaning of a phrase is somewhat more obscure than its literal meaning. Idioms are often employed in the name of brevity or style. In programming languages, idioms often arise from emergent properties of the language that are discovered as it is used to create programs. Each language, because of its distinct features inevitably affords unique idiomatic possibilities. This page, of course, is primarily devoted to describing Tcl idioms. ** Reference ** [https://en.wikipedia.org/wiki/Darmok%|%Darmok]: ** See Also ** [Meta Programming]: presents several distinct but related idioms. [http://www.doc.ic.ac.uk/~np2/patterns/scripting/tcl/index.html%|%Tcl Programming Idioms], by [Nat Pryce]: ** Description ** When this page is referenced, it is often in the sense: : an expression whose meaning is not predictable from the usual meanings of its constituent elements, as ''kick the bucket'' or ''hang one's head'', or from the general grammatical rules of a language, as ''the table round'' for ''the round table'', and that is not a constituent of a larger expression of like characteristics. ** List of Idioms ** `append somevarname {}`: mentioned elsewhere on this Wiki, I believe by [AMG]. Causes `somevarname` to be created if it doesn't exist, without changing its value if it does `[lassign]` using `[foreach]`: `[vwait]` forever: `[if] 0 {...}`: `[proc]` Optional Arguments: `cmdArgs(-linemap)`: args or argv parsing facilitated through use of arrays such as cmdArs(-linemap). This is from the '''Pane Manager''' example, [Book Practical Programming in Tcl and Tk%|%Practical programming in Tcl and Tk], by [Brent Welch]. `[bind] . {console show}`: `if {[[catch {[format] %d%d 3 notanumber}]]} ...`: Validates multiple values against the specified conversion types. [unshared value idiom]: Arrange for a value to be unshared so that Tcl doesn't copy it when it is modified. [Event programming and why it is relevant to Tcl/Tk programming%|%event-driven programming]: `[lassign] {} a b d`: Assigns the empty string to multiple variables. [tags]: When working with [megawidget%|%megawidgets], [tags] can be used to group components [static variables]: `bind . {exec wish $argv0 &; exit}`: [RS]: Rapid restart after edits [The filter idiom]: [Tcl Idioms for Process Management]: ** Self-Testing Source Fragments ** See [main script] ** New Control Structures and Error Reporting ** [Donal Fellows] is good about reporting errors correctly. More precisely, Tcl programmers often knock together handy little control structures ([repeat], [do while], ...) but frankly leave the error-[traceback] as a loose end for some indeterminate future clean-up. Donal's [repeat] example [http://www.man.ac.uk/~zzcgudf/tcl/repeat.tcl] shows how to handle tracebacks cleanly. The heart of it is ====== global errorInfo if {[uplevel #0 [list catch $cmd($rid) ::repeat::msg]]} { append errorInfo "\n (\"repeat\" script)" bgerror $msg Stop $rid return } ====== ** Performance Win with `[regsub]` ** [[Explain Miguel's generalization of 32 to bit-length with self-modifying code in [Binary representation of numbers] as one of several alternatives. regsub-ing a script can be a performance win.]] [[And there's a class of idioms targeted at [Tcl performance], anyway.]] [[I (Miguel) think that [Can you run this benchmark 10 times faster] is also a good example ...]] ** Global Array of Data ** Constants, globals, and so on: reference especially Bob Techentin's post: "One method that many people use is to declare a global array of related data, which you can then reference in your procs with a single global statement. Like this: ====== array set defaultData { color red filetype text cputime 100 } proc myProc {} { global defaultData if {$defaultData(color) eq "green"} { puts {I can't tell the difference between red and green.} } } ====== You can wrap this behavior into a proc, so you don't have to remember to declare the array global all the time: ====== proc const {key} {set ::defaultData($key)} ... if {[const color] eq "green"} {...} ;#RS ====== ** Retrieving Version Information ** Although old-timers cheerfully manipulate [[info tclversion]], $::tcl_version, [[info glob exp*]] (for [Expect]), and so on, the modern idiom for retrieving version information is ====== foreach package {Tcl Expect ...} { puts "The version is [package provide $package]." } ====== ** Widget Root Names ** Several people [http://groups.google.com/groups?ic=1&th=d9ede905e2422e6b] have thought about the not-all-root-names-are-OK-for-your-widget-tree quirk. ** Proc with Automatic Default Lookup ** [TV] I'm not sure what idiom is defined like exactly, but I did a procedure called [pro_args] which allows you to name and assign value to some of many arguments of a procedure, by naming only the ones you want it will automatically lookup defaults for the others. So you'd have a procedure lets say `newarray`: ======none % info args newarray nx ny bn fs ib ipi jb jpi x y ====== of which certain arguments have defaults, and you want to make sure `$x` and `$y` get values of, for instance, `100` and `50` respectively. Of course we could then type something like `newarray a b c d e ... 100 50`, with each argument, also the ones for which we want the default values, filled in or listed. pro_args lets you form such a command by using: ======none % pro_args newarray {{x 100} {y 50}} newarray 3 3 array {} {} {} {} {} 100 50 ====== And when it looks ok, you use ====== eval [pro_args newarray {{x 100} {y 50}}] ====== to execute the command, in this case a [bwise] command to generate an array of blocks. Maybe `[eval]` could be part of the command to save typing. This construction is useful for commands with more than a few or complicated arguments and defaults for them. ** `[lappend]` to Ensure Existence ** '''In modern Tcl, this idiom was rendered inoperable by the fix to the bug and mentioned below.''' [jcw] - To make sure a variable exists (and set it to empty otherwise), you can use lappend: ====== lappend a if {$a ne {ok}} { ... } ====== or even: ====== if {[lappend a] ne {ok}} { ... } ====== Instead of the usual `if {![[info exists a]]} {set a {}}`. [slebetman]: surely that should be: ====== catch {lappend a} ====== unless you don't mind your application unexpectedly exiting or popping up error messages from time to time. [LV]: I'm curious as to what kind of error you were envisioning? I tried missing and present variable, and array references, and `[lappend]` didn't raise any errors there. I even tried this: ====== set a "{" llength $a lappend a ====== and even though llength complains about a having unmatched open brace in the list, lappend didn't complain at all. [slebetman]: Oh yes it does complain: ====== % set a {"} % lappend a x unmatched open quote in list % # Even the example you gave above complains: % set a "{" % lappend a x unmatched open brace in list % info patchlevel 8.4.12 ====== what version are you using? [slebetman]: oops sorry, it appears that it indeed doesn't complain: ====== % lappend a { ====== Can we rely on all future versions of lappend to accept malformed lists in its argument if it has only a single argument or should we treat this as an undocumented, unsupported behavior (bug)? [LV]: I don't know - watch this bug report [http://sourceforge.net/tracker/index.php?func=detail&aid=1570718&group_id=10894&atid=110894] for a response from the maintainers... <> Arts and crafts of Tcl-Tk programming | Glossary