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:
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
if ... fi do ... odI 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 CASE DO | StatementSeq {| StatementSeq} ELSE StatementSeq END WITH <record pfx> DO StatementSeq ENDAlthough Component Pascal used WITH as a type test:
WITH Guard DO StatementSeq {“|” Guard DO StatementSeq} [ ELSE StatementSeq] ENDFrankly 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 nameYou 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 sumBlocks 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 7 % interp alias {} sum {} with {a b} {expr $a+$b} sum % sum 11 31 42NEM 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
do BODY while CONDITIONwrite
while 1 { BODY; # of do..while loop if {!CONDITION} then {break} }The following works too, but is harder to understand:
while {[ BODY expr {CONDITION} ]} {}; # Empty while body