Version 33 of for

Updated 2008-08-24 14:55:27 by wdb

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 expression 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.

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, even if the list is numeric. 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 available, 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 [L1 ], 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


In some languages, the range of a for loop is determined at the start of the loop, and unbounded loops must rather be coded using while. Tcl is not one of those languages (because of C heritage), so for is preferable to while whenever there is a loop variable. In Tcl, you can define a proc range as follows: One case where this happens is a loop over the elements of a list (queue), where processing one element may cause further elements to be appended to the list:

 proc graph_component {graph v} {
    for {set n 0} {$n < [llength $queue]} {incr n} {
        set v [lindex $queue $n]
       set v [lindex $queue $n]
       if {[info exists seen($v)]} then {continue}
       set seen($v) {}
       lappend queue {*}[dict get $graph $v]
    return [array names seen]

}

 }

(graph here is assumed to be a dictionary mapping vertices to their lists of neighbours. v is the vertex whose component one wishes to compute.) graph here is assumed to be a dictionary mapping vertices to their lists The corresponding loop with while is less clear:

 proc graph_component {graph v} {
    set n 0
    while {$n < [llength $queue]} {
        set v [lindex $queue $n]
       set v [lindex $queue $n]
       incr n
       if {[info exists seen($v)]} then {continue}
       set seen($v) {}
       lappend queue {*}[dict get $graph $v]
    return [array names seen]

}

 }

foreach alone wouldn't work, because the queue can grow. A whileforeach combination is possible, but less clear than the simple for:

 proc graph_component {graph v} {
    while {[llength $queue]} {
        set next {}
       set next {}
       foreach v $queue {
          if {[info exists seen($v)]} then {continue}
          set seen($v) {}
          lappend next {*}[dict get $graph $v]
       }
       set queue $next
    return [array names seen]

}

 }

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 [L2 ] 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 RS: The flexibility of the three first arguments to for was directly inherited from C, where you have the same liberties. Lars H: Actually, Tcl gives you greater liberties than C here, because in Lars H: Actually, Tcl gives you greater liberties than C here, because in C the start and next are restricted to being expressions, and expressions in C cannot do any flow control — there's no way to e.g. return or even throw an error from within a C expression — whereas Tcl lets you do these things. aspect: While the for code above suffers in readability, it's heading 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


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.


wdb In Python there is only a foreach aquivalent, and for-loops are done with ranges such as 4..11.

In Tcl, you can define a proc range as follows:

 proc range {from {to ""} {step 1}} {
  if {$to eq ""} then {
    set to $from
    set from 0
  }
  set result {}
  for {set x $from} {$x < $to} {set x [expr {$x + $step}]} {
    lappend result $x
  }
  set result
 }

Now, having this function, you can say:

 foreach i [range 4 11] {puts $i}

which makes your code shorter (but not faster).


See also:


[ Tcl syntax help | Arts and Crafts of Tcl-Tk Programming | Category Command | Category Control Structure ]