while...wend in Tcl

while ... wend in Tcl

Please contribute to this section

Don't be silly.

while {some_expression_is_true} {
    do stuff

That's it.

RS 2005-10-17: While this page is not really topical to Tcl, it illustrates the first generation, if you will, of denoting blocks in programming languages.

0. The oldest languages (Assembler, Fortran etc.) didn't have explicit blocks at all. Only with JMP/GOTO could branching over parts of code be accomplished.

1. ALGOL introduced keywords to mark beginning and end of blocks, where the closing keyword often was the beginning keyword in reverse:

 if ... fi
 do ... od

I think Unix shells extended this to case ... esac (but used do .. done for a change), but nobody seems to have used elihw for an end of while loop. Larry Smith Bliss did. Most painful programming language ever invented. It was designed to let you hurt yourself. loop...pool was also used. Instead, some other combinations were introduced:

 for ... next
 if ... endif (or End If in VB)
 Do ... Loop (VB) 
 Select Case ... End Case
 While ... Wend (VB)
 while <condition> do ... od (Maple)
 for : ... endfor (Metafont)

2. The Pascal language introduced a more orderly grouping, in which begin .. end were put around every block, no matter if part of a control structure, a function body, etc.

3. Finally (?), C simplified this to just use braces: { ... }, and Tcl follows that simplest of all methods. (DKF: Though the use of braces means something else strictly (a particular style of quoting). It just happens to make working with "blocks" incredibly natural.)

Larry Smith Pascal gave rise to Modula/Oberon/Oberon2/Component Pascal which used statement sequences:

 StatementSeq = S1; S2; .... Sn

 IF <boolean exp> THEN StatementSeq ELSE StatementSeq END
 WHILE <boolean exp> DO StatementSeq END
 | StatementSeq
 {| StatementSeq}
 ELSE StatementSeq
 WITH <record pfx> DO StatementSeq END

Although Component Pascal used WITH as a type test:

 WITH Guard DO StatementSeq
  {“|” Guard DO StatementSeq}
  [ ELSE StatementSeq]

Frankly this is the most readable system of those noted, with the cleanest solution to C/JAVA/JAVASCRIPT "dangling else" issues.

NEM Let's not forget Python and Haskell, that use indentation to signify blocks, e.g. (Haskell):

 main = do
         putStr "Enter name: "
         name <- getLine
         putStr "Hello, "
         putStrLn name

You can also use braces and semi-colons in Haskell if you don't like indentation. Also, somewhat related are Ruby and Smalltalk's blocks/closures/thunks, where there is special syntax for creating lambdas, such as (Ruby):

 list = [1,2,3,4,5,6,7,8,9,10]
 sum = 0
 list.each() {|i| sum = sum + 1 }
 puts sum

Blocks can be seen as being lambdas/closures, either with no params (as in C blocks), or with some parameters defined (as in let-blocks in Lisp and other languages). Using closures has the advantage that the environment is captured properly, so you shouldn't need to mess with something like uplevel to sort out scope. Tcl's brace-quoted strings, blocks in Ruby/Smalltalk (and general higher-order programming), monads in Haskell, and macros in Lisp all cover a similar kind of ground in terms of allowing code to be passed around, which goes quite a bit beyond what simple blocks provide. (How much cooler would C be if blocks were first-class?)

RS Do you mean, a mini-closure like this?

 proc with {argl body args} {
    foreach $argl $args break
    eval $body
 % with {a b} {expr $a+$b} 3 4
 % interp alias {} sum {} with {a b} {expr $a+$b}
 % sum 11 31

NEM That's just lambda again, surely? A full closure captures the environment of its definition, so that you can do stuff like:

 set a 0
 map [lambda {x} { incr a $x }] $list
 puts "total = $a"

You can implement this kind of thing in Tcl by writing a [lambda] function that captures the environment (either selectively as in Jim's statics, or the entire thing via introspection: [info locals]). It's not as nice as having special syntax for it, though.

How do you implement a do..while loop in Tcl/Tk?

Lars H: A streamlined implementation is in the control module of tcllib, but for one-off uses it may be easier to use an explicit break. Instead of some



  while 1 {
     BODY; # of do..while loop
     if {!CONDITION} then {break}

The following works too, but is harder to understand:

  while {[
     expr {CONDITION}
  ]} {}; # Empty while body