I was trying to not repeat the same code in different switch blocks and could not figure out how to break out a switch script except to return and exit the procedure.
My question is, Is wrapping the switch in a while loop simply to break, when desired, a terrible thing to do and is there a better way?
It took me awhile, but I realize that a break is not necessary because could set variable in the catch and test outside it to determine when the rest of the code under opt_2 is run (as in the second code example below); but having a break is more clear, especially when the real code is a bit more involved than this example.
Thank you.
% proc SwitchBreak {condition valid} {
set ui_state 1
while { 1 } {
switch -- $condition {
opt_1 {
chan puts stdout opt_1
} opt_2 {
chan puts stdout opt_2
if { [info exists ui_state] && $ui_state == $valid } {
if { [catch { throw {Database Error} {Failed to Write} } result]} {
chan puts stdout "${result}. Rolled back"
set rv 1
set response {Operation Failed}
break
}
}
chan puts stdout {Opt_1 code to run only when\
no valid ui_state or valid state succeeds.}
set rv 0
set response {Successful write.}
} opt_3 {
chan puts stdout opt_3
} default {
chan puts stdout opt_4
}
}
break
}
chan puts stdout {Code after the switch.}
chan puts stdout "rv: $rv; response: $response"
}
% SwitchBreak opt_2 1
opt_2
Failed to Write. Rolled back
Code after the switch.
rv: 1; response: Operation Failed
% SwitchBreak opt_2 0
opt_2
Opt_1 code to run only when no valid ui_state or valid state succeeds.
Code after the switch.
rv: 0; response: Successful write.
No loop, no break.
proc SwitchBreak {condition valid} {
set ui_state 1
switch -- $condition {
opt_1 {
chan puts stdout opt_1
} opt_2 {
chan puts stdout opt_2
set rv 0
if { [info exists ui_state] && $ui_state == $valid } {
if { [catch { throw {Database Error} {Failed to Write} } result]} {
chan puts stdout "${result}. Rolled back"
set rv 1
set response {Operation Failed}
}
}
if { $rv == 0 } {
chan puts stdout {Opt_1 code to run only when\
no valid ui_state or valid state succeeds.}
set response {Successful write.}
}
} opt_3 {
chan puts stdout opt_3
} default {
chan puts stdout opt_4
}
}
chan puts stdout {Code after the switch.}
chan puts stdout "rv: $rv; response: $response"
}
% %
% Switch opt_2 1
opt_2
Failed to Write. Rolled back
Code after the switch.
rv: 1; response: Operation Failed
% SwitchBreak opt_2 0
opt_2
Opt_1 code to run only when no valid ui_state or valid state succeeds.
Code after the switch.
rv: 0; response: Successful write.
While this is legal in that you can write it and it will execute correctly, it seems very ugly to me; a simple
if...elsewould appear to be able to express the intent while actually being clearer. I would even go as far as to say that I would expect that to normally be true.Would there be a case where doing this convoluted thing with a run-once
whileis best? I doubt it... but never say never.A run-once
forwould be slightly better, provided you putbreakin the increment clause. Like that, it's clearer at the top what you are doing.Or you could use
trywith anon breakclause.