for - "For" loop '''for''' ''start test next body'' '''for''' ''start test next body'' http://www.purl.org/tcl/home/man/tcl8.4/TclCmd/for.htm '''For''' is a looping command, similar in structure to the C '''for''' statement. The ''start'', ''next'', and ''body'' arguments must be Tcl command strings, and ''test'' is an [expr]ession string. The '''for''' command first invokes the Tcl interpreter to execute ''start''. Then it repeatedly evaluates ''test'' as an expression; if the result is non-zero it invokes the Tcl interpreter on ''body'', then invokes the Tcl interpreter on ''next'', then repeats the loop. The command terminates when ''test'' evaluates to 0. If a '''[continue]''' command is invoked within ''body'' then any remaining commands in the current execution of ''body'' are skipped; processing continues by invoking the Tcl interpreter on ''next'', then evaluating ''test'', and so on. If a '''[break]''' command is invoked within ''body'' or ''next'', then the '''for''' command will return immediately. The operation of '''[break]''' and '''[continue]''' are similar to the corresponding statements in C. '''For''' returns an empty string. [http://www.tcl.tk/man/tcl/TclCmd/for.htm%|%official reference]: Note: ''test'' should almost always be enclosed in braces. If not, variable substitutions will be made before the ''for'' command starts executing, which means that variable changes made by the loop ''body'' will not be considered in the expression. This is likely to result in an infinite loop. If ''test'' is enclosed in braces, variable substitutions are delayed until the expression is evaluated (before each loop iteration), so changes in the variables will be visible. For an example, try the following script with and without the braces around '''$x<10''': for {set x 0} {$x<10} {incr x} { puts "x is $x" } (From: [TclHelp]) See also: [TclHelp] ---- The bracing of ''test'' will result in '''expr''' parsing the contents. But in braced expressions, '''expr''' does not tolerate operators to be passed in as variables. If you want to do that, call an explicit '''[expr]''' without braced condition (but inside brackets and braces, as explained above), so the Tcl parser substitutes that in each loop repetition: set op "<" for {set x 0} {[expr $x $op 10]} {incr x} {puts "x is $x"} ;#RS ---- A poster to comp.lang.tcl mentioned the following problem. Some code was set up like this: ====== set size [getresult from operation] for {set i 0} {$i<$size} {incr i} { set workingarray($i) 0 } ====== However, due to a mistake, the output from getresult changed at one point from being a number to being a string. Rather than causing for to raise an error, the bug caused the for loop to loop thousands of time, until in the poster's case, memory was used up. While ====== expr $i < $size ====== would raise an error ====== expr {$i<$size} ====== as well as the use within the for only returns a 1, causing the loop to run forever. Test your variables to ensure they actually have the type of value you expect, after getting values from a user or external source. ---- In some situations, using a '''[foreach]''' with a fixed list is more convenient than a '''for''', compare: foreach i {1 2 3 4 5} {... for {set i 1} {$i <= 5} {incr i} {... or, instead of unrolling a range, you can wrap one ''for'' for sugaring: proc range {from "to:" to} { set res [list] for {set i $from} {$i<=$to} {incr i} {lappend res $i} set res } foreach i [range 1 .. 5] {... This is, however, slower than `for`. '''[Foreach]''' is generally better style in non-numeric looping. Those accustomed to writing in C sometimes find this a difficult habit to learn, because they think of an indexed array where a Tcl coder writes simply set color_list "red blue umber mauve" foreach color $color_list {...} ---- [AMG]: Sometimes I need to chew through a list and conditionally edit, replace, or remove elements. I can easily read "copies" of each element in the list using [['''foreach''']], but when the condition triggers I need the list index for [[[lreplace]]], [[[lset]]], [[[linsert]]], and the like. What's the best way to handle this? Option the first: set list {0 1 2 3 4 5 6} set index 0 foreach elem $list { if {$elem % 2 == 0} { lset list $index [expr {-$elem}] } incr index } Option the second: set list {0 1 2 3 4 5 6} for {set index 0} {$index < [llength $list]} {incr index} { set elem [lindex $list $index] if {$elem % 2 == 0} { lset list $index [expr {-$elem}] } } set list {0 1 2 3 4 5 6} set result [list] foreach elem $list { if {$elem % 2 == 0} { lappend result [expr {-$elem}] } else { lappend result $elem } } set list $result Better still would be a list comprehension (e.g., [[[lcomp]]]), but to me it seems so pricy that I usually avoid it. Better still would be a list comprehension (e.g., `[lcomp]`), but to me it [Lars H]: Good question; I often find myself wondering the same thing. I suspect that rebuilding the list is on the whole the best approach, when possible (I think dragging the index around is sometimes unavoidable). An nice thing about the rebuild method is that it allows for more functional ways of writing the body; in this case the extreme is probably set list {0 1 2 3 4 5 6} set result [list] foreach elem $list { lappend result [expr { $elem % 2 == 0 ? -$elem : $elem }] } set list $result [AMG]: If your code is functional, does that mean mine is dysfunctional? :^) Seriously, we should look into list comprehensions a bit more. Just how much do they cost, when implemented in Tcl or C? Can something be done in C to allow for a better Tcl implementation? How do list comprehensions compare to writing the equivalent [['''for''']]s/[[[foreach]]]es? Which is more readable and maintainable? How can things be improved? And so on. [AMG]: If your code is functional, does that mean mine is dysfunctional? :^) With [[[lcomp]]], the above is written: set list [lcomp {[expr {$x * -1 ** (1 - $x % 2)}]} x {0 1 2 3 4 5 6}] Yeah, maybe that exponentiation is going overboard, but I couldn't help myself. :^) Yeah, maybe that exponentiation is going overboard, but I couldn't help myself. ''[Lars H]: If you rewrite that expression using the ?: operation, you'll see that my code was just an unrolled version of your [lcomp]. The last three examples thus demonstrate the variation from imperative style to purely functional style.'' `[lcomp]` can be modified to `[eval]` its first argument, perhaps in a [[[lcomp]]] can be modified to [[[eval]]] its first argument, perhaps in a child interpreter with an [['''emit''']] command. That would allow the above to be written in a hybrid functional-imperative notation: set list [lcomp { if {$x % 2 == 0} { emit [expr {-$x}] } else { emit $x } } x {0 1 2 3 4 5 6}] Plus, if [['''emit''']] can take multiple arguments and/or can be called multiple times, this syntax allows for single input elements to result in any number (including zero) of output elements. Hmm. Plus, if '''`emit`''' can take multiple arguments and/or can be called Hey, joyous idea. The first argument gets passed unmodified to [[[eval]]] (or [[[interp eval]]]), which should (??) allow Tcl to bytecode compile it. Bonus! But the nests of [[[foreach]]]es would still be pieced together every time [[[lcomp]]] is called, so don't put [[[lcomp]]] in a loop. Hey, joyous idea. The first argument gets passed unmodified to `[eval]` (This is topical because it's an attempt to find alternatives to [['''for''']] for list processing. But we might want to move to another page before long. Hey, another idea: ''dictionary comprehensions!'') (This is topical because it's an attempt to find alternatives to `for` for [NEM] ''12 June 2006'': List comprehensions can be generalised to allow queries over a range of different data structures. At the end of this road are things like ''monad comprehensions'' [http://www.inf.uni-konstanz.de/~grust/files/thesis-GI.pdf], and Microsoft's new [LINQ] framework for .NET. [NEM] 2006-06-12: List comprehensions can be generalised to allow queries over proc map {cmd mylist} { set r "" foreach e $mylist {lappend r [$cmd $e]} set r } proc negate-even {x} {expr {$x%2==0 ? -$x : $x}} map negate-even {0 1 2 3 4 5 6} With [lambda], it could be even simpler. - [RS]: [lmap] is a lambda/map compromise pretty much in Tcl's [foreach] spirit. ---- ''[lexfiend] 2006-Jun-12'' - While most people think of [for] in terms of C-style integer iteration or list-walking, [DKF] provides a neat reminder in [http://groups.google.com/group/comp.lang.tcl/browse_frm/thread/187c51d56fe9efe6/4c0d7360873f54b3?tvc=1#4c0d7360873f54b3] that ''start'', ''test'' and ''next'' could do many other things too. The code fragment in question: for {fconfigure $pipe -eofchar \u0000} { } {seek $pipe 1 current} { } {seek $pipe 1 current} { } } fconfigure $pipe -eofchar \u0000 while {1} { # Read up to the next eof char, as configured set record [read $pipe] if {[string length $record]} { # process $record here } else { break } # skip over the eof char seek $pipe 1 current } Of course, the downside to using this sort of reductionist construct is that it can sometimes be hard to be sure your logic is correct. 8-) - [RS]: The flexibility of the three first arguments to for was directly inherited from [C], where you have the same liberties. ---- See also: * [break] * [continue] * [expr] * [foreach] * [if] * [while] * [fold] / [map] / [zip] etc ---- [[ [Tcl syntax help] | [Arts and Crafts of Tcl-Tk Programming] | [Category Command] | [Category Control Structure] ]]