break

Difference between version 34 and 35 - Previous - Next
'''`[http://www.tcl.tk/man/tcl/TclCmd/break.htm%|%break]`''', a [Tcl Commands%|%built-in] [Tcl] command, aborts a looping command.



** See Also **

   [continue]:   
   
   [return]:   

   [for]:   
   
   [foreach]:   
   
   [while]:   



** Synopsis **

'''break'''


 
** Description **

'''`break`''', which is equivalent to '''`[return] -level 0 -code break`''',
cuts short the evaluation of a script in iterative routines such as `[for]`,
`[foreach]`, or `[while]`, cancels any further iterations, and causes those
routines to return.  `[catch]` and `[try]` can be used to implement customized
handling of `[break]`.  This is done, for example, in `[New Control
Structures%|%custom control structures]`, and sometimes in Tk event bindings.



** Documentation **

   [http://www.tcl.tk/man/tcl/TclCmd/break.htm%|%official reference]:   



** Examples **

Print a line for each of the integers from 0 to 5:

======
for {set x 0} {$x<10} {incr x} {
    if {$x > 5} {
        break
    }
    puts "x is $x"
}
======

This is the same as:
======
for {set x 0} {$x<10} {incr x} {
    if {$x > 5} {
        return -level 0 -code break
    }
    puts "x is $x"
}
======



** Discussion **

One surprising use of break is to make sure a `[foreach]` loop runs exactly
once (because we're only interested in the list assignment, not the actual
body):

======
foreach {a b} [list $b $a] break ;# (1)
======

[RS] 2006-04-20: This code for swapping two variables can however be had
simpler:

======
foreach a $b b $a break          ;# (2)
======

[Lars H]: No, that sets a to the first element of b and b to the first element
of a, which isn't in general the same thing as swapping the values.

[RS]: True. I was thinking in terms of scalars only... For values parsable as
lists, approach (1) is better.

[justinalanbass]: This has nothing to do with break; the body can just as
effectively be replaced with anything.

======
foreach a $b b $a {set c 1}
======

[RLE] 2015-04-30: This is not the same. The [break] is in fact important.  This idiom is the traditional way to perform an [lassign] in Tcl 8.4 and before.  To emulate lassign, you want the foreach to only iterate once, therefore the [break] is required to assure only one iteration.

With your alternate version, the foreach loop will iterate a number of times equal to the list length of the longer list, the variables will receive the last elements of the lists (not the first elements), and one of the variables might even end up empty (if the lists are of different lengths).

Your version also introduces a subtle data dependent heisenbug.  If the contents of $a and $b are simple scalars, it will appear to work properly.  And will likely work for quite a long time.  But the moment a string that is not parseable as a list happens to be placed into one (or both) of the variables, you'll get what appears to be a weird error message about "can not parse list from string".  Murphy's law postulates that this data dependency will surface several years after you wrote the code, in the middle of the night, while you are away on a lengthy vacation, causing all kinds of havoc for something that up until that point had worked just fine.  Or that it will surface several years later, when you modify something unrelated elsewhere in your code, and happen to create a non-parseable string for the foreach in the process.  At which point you'll get a 'spooky bug at a distance' situation arising because your change and the bug will seem wholly unrelated.

----

[escargo] 2004-07-13:   I recently noted that in [Icon Programming
Language%|%Icon], the ''break'' expression takes an optional expression just
like the '''return''' expression does.  This allows a bit more information to
come out of a break.  (It's also probably not what Tcl considers an exception.)

[AMG]: [Perl]'s break expression takes an argument which gives the number of
levels to break.  This avoids one common need for [goto]: breaking out of
nested loops.  Tcl has another way to do this, though:

======
try {
    foreach x {a b c} {
        foreach y {d c f} {
            puts [list $x $y]
            if {$x eq $y} {
                return -level 0 -code 5
            }
        }
    }
} on 5 {} {}
======

Some sugar:

======
proc loop {script} {tailcall try $script on 5 {} {}}
proc stop {} {return -code 5}
loop {
    foreach x {a b c} {
        foreach y {d c f} {
            puts [list $x $y]
            if {$x eq $y} {
                stop
            }
        }
    }
}
======

Or in a more [Perl]-like fashion:

======
rename unknown unknown_
rename break break_

proc unknown {args} {
    switch -regexp [lindex $args 0] {
        "^[A-Z_]+:$" {uplevel 1 with_label $args}
        default {uplevel 1 unknown_ $args}
    }
}

proc with_label {l args} {
    set l [string range $l 0 end-1]
    tailcall try $args \
    trap [list BREAK $l] {} {}
}

proc break {args} {
    if {$args eq ""} {
        return -code break
    } else {
        set l [lindex $args 0]
        return -code error -errorcode [list BREAK $l]
    }
}
LOOP: whil\
foreach 1x {a b c} {
    wforeachi y {d c f} {
        puts [list $x $y]
        if {$x eq 1$y} {
            break LOOP
        }
    }
}
======

<<categories>> Tcl syntax | Arts and Crafts of Tcl-Tk Programming | Command | Control Structure