100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Programming

Loops in Tcl

Master Tcl's while, for, and foreach loops, along with break and continue for controlling repeated execution.

Control Flow & ProceduresBeginner8 min readJul 10, 2026
Analogies

Looping Constructs in Tcl

Tcl provides three core looping commands: while, for, and foreach. while {condition} {body} repeats the body as long as the braced condition evaluates true, re-checking it before each iteration. for {init} {test} {next} {body} takes four separate brace-delimited arguments, an initialization script, a test expression, a per-iteration update script, and the loop body, executed in that order each pass, closely mirroring C's for loop but with every clause as its own Tcl script rather than baked-in syntax. foreach varname list body is the idiomatic way to walk over a Tcl list without manual indexing.

🏏

Cricket analogy: Net practice sessions use different loop styles: a bowler doing 'while there's daylight, keep bowling' is a while loop, a fixed 'bowl exactly 6 overs' drill is a for loop, and 'go through each fielder in the slip cordon and check their position' is a foreach loop over a list of fielders.

The while and for Loops

The for loop's four arguments are all ordinary Tcl scripts evaluated at specific points: for {set i 0} {$i < 10} {incr i} {puts $i} initializes i once, tests $i < 10 before every iteration, runs incr i after every iteration, and runs the body in between. Because test is evaluated by expr internally, it must be a valid boolean expression each time, and because next runs after the body, a break inside the body will skip the final increment for that pass. A while loop is simpler and better suited when there's no natural counter, such as reading input until end-of-file: while {[gets $chan line] >= 0} {...}.

🏏

Cricket analogy: The four-part structure of for {set i 0} {$i < 10} {incr i} {...} is like an over: init zeroes the over counter, test checks 'is the innings still under 10 overs', next increments the count after each over, and the body is the actual bowling -- each part runs at its own moment.

The foreach Command

foreach x {a b c} {puts $x} assigns each list element to x in turn and runs the body once per element. foreach also supports iterating multiple lists in parallel by supplying several varname/list pairs, e.g. foreach {name score} {Alice 90 Bob 85} {...} walks the flat list two elements at a time, and foreach a $list1 b $list2 {...} walks two separate lists side by side, padding the shorter one with empty strings if their lengths differ.

🏏

Cricket analogy: foreach {name score} {Kohli 82 Rohit 45 Bumrah 3} {...} walking a flat list two at a time mirrors reading a scorecard row by row, pulling a batter's name and their score together in each pass rather than as two separate lists.

break, continue, and Loop Control

break immediately exits the innermost enclosing loop, skipping any remaining iterations, while continue skips straight to the next iteration's test/update step without running the rest of the current body. Both work identically inside while, for, and foreach. A subtle bug beginners hit is writing for {set i 0} {$i < 10} {} {...} and forgetting to increment i anywhere in the body -- since the next script is empty, the loop runs forever unless something inside the body itself updates i or calls break.

🏏

Cricket analogy: A captain calling for a bowling change mid-over is like break, exiting the current spell immediately regardless of how many balls were planned; skipping a wide ball without counting it toward the over is like continue, moving straight to the next delivery.

tcl
# Sum numbers 1 through 10 using for
set total 0
for {set i 1} {$i <= 10} {incr i} {
    set total [expr {$total + $i}]
}
puts "Sum: $total"

# Iterate a list with foreach, skip and break
foreach fruit {apple banana cherry durian elderberry} {
    if {$fruit eq "durian"} {
        continue
    }
    if {$fruit eq "elderberry"} {
        break
    }
    puts "Fruit: $fruit"
}

foreach can walk multiple lists at once: foreach a $list1 b $list2 {...} binds a and b from two separate lists in lockstep, padding the shorter list with empty strings if the lists differ in length. This is often cleaner than manually indexing with lindex inside a for loop.

for {set i 0} {$i < 10} {} {body} with an empty next clause will loop forever unless the body itself updates i or calls break -- Tcl does not automatically increment anything for you. Also remember the test clause must be inside braces ({$i < 10}, not $i < 10) so it's re-evaluated fresh on every pass instead of being computed once at parse time.

  • while {cond} {body} repeats while its braced condition is true, re-testing before every iteration.
  • for {init} {test} {next} {body} takes four separate script arguments run at four distinct points in each pass.
  • foreach varname list {body} is the idiomatic way to walk a Tcl list without manual indexing.
  • foreach can bind multiple variables per list, or walk several lists in parallel with multiple varname/list pairs.
  • break exits the innermost loop immediately; continue skips to the next iteration's test/update step.
  • Leaving the for loop's next clause empty is legal but risks an infinite loop if nothing in the body updates the loop variable.
  • Keep loop test expressions inside braces so expr re-evaluates variables fresh each iteration instead of once at substitution time.

Practice what you learned

Was this page helpful?

Topics covered

#Programming#TclTkStudyNotes#LoopsInTcl#Loops#Tcl#Looping#Constructs#StudyNotes#SkillVeris#ExamPrep