From a news:comp.lang.tcl posting by Jeffrey Hobbs on Aug 15, 2000:
Brandon Hoppe wrote: I need a loop equivalent to the do-while loop. Is there one built in?
A do-until construct was one of the Tcl2K expert questions, with the undisputed winner being:
# Done by Reinhard Max # at the Texas Tcl Shoot-Out 2000 # in Austin, Texas. proc do {script arg2 {arg3 {}}} { # # Implements a "do <script> until <expression>" loop # The "until" keyword ist optional # # It is as fast as builtin "while" command for loops with # more than just a few iterations. # if {[string compare $arg3 {}]} { if {[string compare $arg2 until]} { return -code 1 "Error: do script ?until? expression" } } else { # copy the expression to arg3, if only # two arguments are supplied set arg3 $arg2 } set ret [catch { uplevel $script } result] switch $ret { 0 - 4 {} 3 {return} default { return -code $ret $result } } set ret [catch {uplevel [list while "!($arg3)" $script]} result] return -code $ret $result }
You can alter this from do-until to do-while by changing the uplevel'ed while to not !().
I'll leave the analysis up to the reader, because this is an excellent example of control construct creation.
RS: If you change the proc line to
proc do {script {arg2 {}} {arg3 {}}} { if {![string length $arg2$arg3]} {set arg2 0}
you win the added functionality of calling do $body which works like the not too unfrequent while 1 $body. Switching between while and until can of course also be built in...
if {[string compare $arg3 {}]} { switch -- $arg2 { until {set bool "!"} while {set bool ""} default {return -code 1 "usage: do script ??until|while? expr?"} } } ... set ret [catch {uplevel [list while ${bool}($arg3) $script]} result]
rmax: This "do while|until" loop is now a part of tcllib's control package.