2

In the below code once I hit check_access as 0 how do I preserve the value and hit the if condition below ($check_root && $check_access) . Break will only terminate the inner loop. But the other loops will continue as per me.

   } else {
           set check_access 0
           break
         }
      }
   }
   if {$check_root && $check_access} {
    set result 1
  } else {
    set result 0
  }
Zuckerberg
  • 205
  • 6
  • 15

2 Answers2

4

The break and continue operations only go out one level of looping. If you need more than that, consider refactoring so that you can just return. Alternatively, try a custom exception in Tcl 8.6:

try {
    foreach a $longList1 {
        foreach b $longList2 {
            if {[someCondition $a $b]} {
                # Custom non-error exception
                return -level 0 -code 123
            }
        }
    }
} on 123 {} {
    # Do nothing; we're out of the loop
}
Donal Fellows
  • 133,037
  • 18
  • 149
  • 215
  • This is a nice way , But being custom I dont know if it will work in my prod environment if they are using old tcl versions . But this is definitely good to know that there is almost a goto in tcl . thanks – Zuckerberg Jan 19 '13 at 20:59
  • @sudeep That's _exactly_ why I suggest refactoring. If you've got something complicated enough to need a multi-level break, you've got a good candidate for splitting into simpler pieces that don't need such complexity. (Also, 8.6.0 is now out and recommended for production use.) – Donal Fellows Jan 19 '13 at 21:25
4

break jumps to the end of the innermost loop only, and Tcl has no goto. But return, unless it's inside a catch or similar, exits a procedure which is like jumping to the end of it. So if you make the outermost loop the last command of the procedure (if your code is top-level, you have to put it in a procedure first to be able to use return), you can use return as a multi-break. Just move the commands after the loop out of the procedure and into the caller's code:

proc callMe {} {
  foreach ... {
    foreach ... {
      if ... {
        return
      }
    }
  }
  # move this code from here...
}

callMe
# ...to here

Another way is to put in extra tests:

set done 0
foreach ... {
  foreach ... {
    foreach ... {
      if ... {
        set done 1
        break
      }
    }
    if {$done} {break}
  }
  if {$done} {break}
}
potrzebie
  • 1,768
  • 1
  • 12
  • 25