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] ---- **When not to use [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 {...} ---- 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} {... Some find the idea of using [foreach] on a range of integers so nice that they wrap an actual '''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 the '''for'''. This is, however, slower than `for`. The main difference between [for] and [foreach] when iterating over a list is that with [for] the index into the list is avilable, whereas with [foreach] it is not. [foreach] can however be preferable even if the list index is needed. What would traditionally be coded as for {set index 0} {$index < [llength $list]} {incr index} { # Now do something using both $index and $item ... } } is actually faster as the following [foreach]: set index -1; foreach item $list {incr index ... } } The reason to [incr] ''index'' first in the loop body is that this makes [continue] do the right thing. In order for `[continue]` to do the right thing, `[incr] index` comes first in [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. With `[lambda]`, it could be even simpler. [RS]: `[lmap]` is a lambda/map compromise pretty much in Tcl's ---- **When to use [for] rather than [while]** ---- ''[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. [RS]: The flexibility of the three first arguments to for was directly [aspect]: While the [for] code above suffers in readability, it's heading down a useful path. Lispers would tend to look for an underlying abstraction which is easy in tcl: proc with-records {eofchar $_record body} { set _eofchar [fconfigure $pipe -eofchar] for {fconfigure $pipe -eofchar $eofchar} { [string length [set record [read $pipe]]] [string length [set record [read $pipe]]] uplevel 1 $body uplevel 1 $body fconfigure $pipe -eofchar $_eofchar } } In writing this construct, the need to reset eofchar at the end of the look was exposed and easily addressed. Also I'd tend to use the default name $_ for the record instead of having to explicitly provide it, but that's a matter of taste. As is the name of the procedure, which I'm not entirely happy with. But the point is that making [New Control Structures] is easy: you don't have to be shoehorn your problem into [for], [foreach] and [while] like in most other languages. In writing this construct, the need to reset `-eofchar` at the end of the look ---- **Tips and tricks on [for]** A poster to comp.lang.tcl mentioned the following problem. Some code was set up like this: A poster to [comp.lang.tcl] mentioned the following problem. Some code was set set size [getresult from operation] for {set i 0} {$i<$size} {incr i} { set workingarray($i) 0 set workingarray($i) 0 ====== However, due to a mistake, the output from `getresult` changed at one point 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 ====== expr {$i<$size} ====== as well as the use within the for only returns a 1, causing the loop to run forever. , as well as the use within the `for` only returns a 1, causing the loop to run Test your variables to ensure they actually have the type of value you expect, after getting values from a user or external source. A quick way to [assert] that a value is an integer is to [incr] it by 0, like so: set size [getresult from operation] incr size 0 for {set i 0} {$i<$size} {incr i} { set workingarray($i) 0 set workingarray($i) 0 ====== ---- <> Arts and Crafts of Tcl-Tk Programming | Tcl syntax help | Command | Control Structure 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 Note that not bracing the [expr] expression ''will'' mean there are two substitution rounds. This can lead to problems if some substituted value is not a simple number. Alternatively, use quotes and backslashes: set op "<" for {set x 0} "\$x $op 10" {incr x} {puts "x is $x"} This substitutes ''op'' before calling [for], but ''x'' only when the expression is evaluated. This technique makes it easier to handle complex substituted values, but the need to escape all `$` signs can be a burden in complex expressions. ---- 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] ]]