'''`[https://www.tcl-lang.org/man/tcl/TclCmd/while.htm%|%while]`''', a [Tcl commands%|%built-in] Tcl [command], iteratively [Many ways to eval%|%evaluates] a [script] while the provided expression is true. ** See Also ** [for]: [if]: [expr]: [foreach]: ** Synopsis ** : '''`while`''' ''`expression body`'' ** Description ** '''`while`''' evaluates ''`body`'' as long as `[expr%|%expression]` is true and then returns the [empty string]. Within ''`body`'', `[continue]` immediately progresses to the next evaluation of ''`expression`'', and `[break]` causes `while` to terminate immediately. Commands such as `[exit]`, `[return]` and `[tailcall]` also teminate `while`. ''expression'' should almost always be [Brace your expr-essions%|%enclosed in braces]. If not, Tcl perfoms [substitution%|%substitutions] as usual before calling `while`, which then also performs substitutions while evaluating ''`expression`''. This may result in [double substitution], or it may result in a variable only being substituted before the first iteration when the author expected it to be substituted before every iteration. In such a case `while` never terminates because the value of the expression never changes. Enclosing ''expression'' in braces means Tcl doesn't perform substitutions, leaving `while` to perform any substitutions itself each time it evaluates the expression. The following example illustrates the difference: ====== set x 0 # warning: this never ends while $x<10 { puts "x is $x" incr x } # this time $x is what was intended while {$x<10} { puts "x is $x" incr x } ====== The standard idio to create a loop that continues forever is: ====== while 1 { ... } ====== Any other true value may be used in place of `1`. ** Constraining Resource Usage ** While discussing at the [Tcl Chatroom] a while that would be safe in safe interpreters [GPS] came up with these for Tcl 8.4: ====== rename while real.while proc do.while {cond body} { if {$cond} {uplevel 2 $body} } proc while {cond body} { set start [clock seconds] real.while 1 { do.while $cond $body if {[clock seconds] >= ($start + 600)} { return -code error {too much time used} } } } ====== [GPS]: And yes I know that $cond should be uplevel'd... [GPS]: Note that 600 seconds is somewhat crazy. I think 30 or 20 is good. [GPS]: Another trick would be to prevent calls to while while within a while. [GPS]: There could be a global lock (protected from set) that would just return -code error "existing while running" if the lock is active. [dkf]: Why the do.while in there? [GPS]: Just seemed easier to type out do.while and think of this as units rather than one big proc [GPS]: Here's another without the do.while: ====== rename while real.while proc while {cond body} { set start [clock seconds] real.while 1 { if {[uplevel [linsert $cond 0 expr]]} { uplevel $body } else return if {[clock seconds] > ($start + 10)} { return -code error "time limit exceeded in while loop" } } } ====== [US] See also [DoS] <> Arts and crafts of Tcl-Tk programming |Tcl syntax help | Command | Control Structure