Version 0 of do...until in Tcl

Updated 2000-11-09 11:53:28

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 <[email protected]>
 # 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]