Version 12 of switch

Updated 2002-11-14 12:55:14

Documentation for the Tcl switch command can be found at http://www.purl.org/tcl/home/man/tcl8.4/TclCmd/switch.htm


RS Make sure you always write "the switch to end all switches", "--", if there is the slightest possibility that faulty or unexpected data (i.e., beginning with a dash) may occur - they raise a data-driven syntax error which does not make a good impression on end-users.

 switch -- $foo {...}  ;# robust for all values of foo

In the form of the switch command where all patterns and bodies are in the last argument, this argument is technically a string which will be parsed by Tcl as a list. The rules for how a string is parsed as a list can be found on the lindex manual page [L1 ]. The difference here between a whitespace-delimited substring and a list element parsed from a string is usually negligible, but one must sometimes take them into account to get the right amount of quoting in place. Regexp patterns are particularly easy to overquote.


Coding style for switch is tricky. Recently on comp.lang.tcl there was an exchange about getting switch to work right. The user had originally typed:

 switch $::errorCode {
  $NOTFOUND {
        puts "page not found "
  }
  default {
        puts "Program encountered code $::errorCode"
        break
  }
 }

and was frustrated because the application kept taking the default branch.

A well known Tcl pundit suggested:

 switch $::errorCode "
    $NOTFOUND {
        puts "page not found "
    }
    default {
        puts "Program encountered code $::errorCode"
        break
    }
  "

so that Tcl had a chance to substitue the value of $NOTFOUND. However, the follow up, by Ken Jones said it best:

you don't want that (unless you're doing some very, very, very tricky stuff). Quoting switch's pattern/action block with "" allows substitutions within the entire argument. So, yes you get the $URL_NOT_FOUND variable substituted. But you also get the contents of the actions substituted before switch even gets called.

Instead, we want the "alternate" syntax of switch, where you provide each pattern and its corresponding action as separate arguments to switch, rather than as a monolithic pattern/action quoted argument. Here's a correctly working example of the above code:

 set NOTFOUND "value"
 set errorCode "nonsense"

 switch -- $::errorCode \
    $NOTFOUND  {
        puts "page not found"
        } \
    default {
        puts "Program encountered code $::errorCode"
        break
    }

KBK - I dislike both of these. I tend to think of a switch as a selection among fixed alternatives, and substitution in the cases confuses me. I'd have just written:

  if { [string equal $::errorcode $NOTFOUND] } {
      puts "page not found"
  } else {
      puts "Program encountered code $::errorCode"
      break
  }

The above sample was, of course, intended to be brief, and didn't show the other several dozen switch cases . For a single comparison, I agree with KBK. But if I have more than one or two of these types of comparisons, then I know I LV prefer a switch.


With switch -regexp, you can specify abbreviations of a flag to be switched on like this:

 switch -regexp -- $variable {
  -h(e(lp?)?)?             {...}
  -h|-he|-hel|-help|-ayuda {...}
  -\\? { ... }                     ;$ Match -? flag
  "(?x) - | -h | -help" {do stuff} ;# extended RE syntax
 }

without the -regexp, you would write:

 switch -- $variable {
  -h - -he - -hel - -help { ... }
 }

LV I really find using - as a seperator between switch case alternatives to be counter-intuitive; normally one uses | for that sort of thing .


See also ranged switch


Tcl syntax help - Arts and crafts of Tcl-Tk programming - Category Command