Version 2 of do...until in Tcl

Updated 2002-12-04 10:31:06

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 "util" 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.