[samoc]: `retry` is `try` more than once. usage: `retry count_var count body ?handler...? ?finally script?` e.g. try a few times to get a message through if the network is busy ... ====== retry count 3 { send_message "Hello" } trap NetworkBusy {} {} ====== ... or, retry with exponential backoff... ====== retry count 10 { send_message "Hello" } trap NetworkBusy {msg info} { puts "$msg" after [expr {$count * $count * 100}] } ====== It might occasionally be useful to retry for all errors: ====== retry count 3 { send_message "Hello" } on error {} {} ====== Implementation: ====== proc retry {count_var count body args} { # Retry "body" up to "count" times for exceptions caught by "args". # "args" is a list of trap handlers: trap pattern variableList script... # The retry count is made visible through "count_var". assert string is wordchar $count_var assert string is integer $count assert {[lindex $args 0] in {trap on finally}} upvar $count_var i if {[lindex $args end-1] == "finally"} { set traps [lrange $args 0 end-2] set finally [lrange $args end-1 end] } else { set traps $args set finally {} } for {set i 1} {$i <= $count} {incr i} { # Try to execute "body". On success break from loop... uplevel [list try $body {*}$traps on ok {} break] # On the last attempt, suppress the trap handlers... if {$i + 1 == $count} { set traps {} } } } ====== ---- [AMG]: Some more explanation would be welcome. ''-- [samoc] sorry about the original unexplained version. Revised version is above.'' This code appears to retry an operation a specified number of times, swallowing configurable errors and other such abnormal returns all but the final time, though giving the user the ability to specify the handlers. Your example shows waiting one second between retries. Is this code intended to dodge a race condition? Maybe find another way to design your system such that the race doesn't exist. ''-- [samoc]: This code is intended to deal with interfacing to real-world non-determinism (networks, people, actuators, sensors etc...)'' [RLE] (2014-05-25): [samoc]: Now you've posted, effectively, non-working code because you've left out your custom '[assert]' implementation. However, if you are using Tcllib's [control%|%assert] then you need a "package require control" before defining the [proc]. [AMG]: This [[assert]] looks fairly straightforward. From how it's being used, I assume this custom [[assert]] could be the following: ====== proc assert {test args} { if {[llength $args]} { set test \[[concat [list $test] $args]\] } if {![uplevel expr [list $test]]} { error "assert failure: $test" } } ====== [samoc]: In fact, my version of [assert] looks like this: ====== proc assert {args} { # usage: assert command args... # or: assert {expression} if {[llength $args] == 1} { if {[uplevel expr $args]} { return } } else { if {[{*}$args]} { return } } return -code error \ -errorcode [list assert $args] \ "Assertion Failed:\n $args" } interp alias {} require {} assert ====== ... but there is plenty of other information about [Assertions] elsewhere on the wiki. The real version of `retry` that I use in my own code follows... ''The version above is edited to make it more like plain Tcl. I have a special prize for anyone who can guess what language my custom version of `proc` is inspired by :)'' ====== proc retry {count_var count body args} { Retry "body" up to "count" times for exceptions caught by "args". "args" is a list of trap handlers: trap pattern variableList script... The retry count is made visible through "count_var". } require { is wordchar $count_var is integer $count {[lfirst $args] in {trap on finally}} } do { upvar $count_var i if {[lindex $args end-1] == "finally"} { set traps [lrange $args 0 end-2] set finally [lrange $args end-1 end] } else { set traps $args set finally {} } for {set i 1} {$i <= $count} {incr i} { # Try to execute "body". On success break from loop... uplevel [list try $body {*}$traps on ok {} break {*}$finally] # On the last attempt, suppress the trap handlers... if {$i + 1 == $count} { set traps {} } } } ====== [RLE] (2014-05-26): First guess, it looks quite Lisp like, with a doc-string, a let clause to define variable bindings, although in your case it is assertions, and a body to execute. <> Control Structure