Switch statement

In computer programming languages, a switch statement is a type of selection control mechanism used to allow the value of a variable or expression to change the control flow of program execution via a multiway branch.

Switch statements exist in most high-level imperative programming languages such as Pascal, Ada, C/C++, C# and Java, and in many other types of language, using such keywords as `switch`, `case`, `select` or `inspect`.

Switch statements come in two main variants: a structured switch, as in Pascal, which takes exactly one branch, and an unstructured switch, as in C, which functions as a type of goto. The main reasons for using a switch include improving clarity, by reducing otherwise repetitive coding, and (if the heuristics permit) also offering the potential for faster execution through easier compiler optimization in many cases.

 ` switch (age) { case 1: printf("You're one."); break; case 2: printf("You're two."); break; case 3: printf("You're three."); break; case 4: printf("You're four."); break; default: printf("You're neither!"); break; } `

History

In his 1952 text Introduction to Metamathematics, Stephen Kleene formally proved that the CASE function (the IF-THEN-ELSE function being its simplest form) is a primitive recursive function, where he defines the notion `definition by cases` in the following manner:

"#F. The function φ defined thus
φ(x1 , ... , xn ) =
• φ1(x1 , ... , xn ) if Q1(x1 , ... , xn ),
• . . . . . . . . . . . .
• φm(x1 , ... , xn ) if Qm(x1 , ... , xn ),
• φm+1(x1 , ... , xn ) otherwise,
where Q1 , ... , Qm are mutually exclusive predicates (or φ(x1 , ... , xn) shall have the value given by the first clause which applies) is primitive recursive in φ1, ..., φm+1, Q1, ..., Qm+1.[1]

Kleene provides a proof of this in terms of the Boolean-like recursive functions "sign-of" sg( ) and "not sign of" ~sg( ) (Kleene 1952:222-223); the first returns 1 if its input is positive and −1 if its input is negative.

Boolos-Burgess-Jeffrey make the additional observation that "definition by cases" must be both mutually exclusive and collectively exhaustive. They too offer a proof of the primitive recursiveness of this function (Boolos-Burgess-Jeffrey 2002:74-75).

The IF-THEN-ELSE is the basis of the McCarthy formalism: its usage replaces both primitive recursion and the mu-operator.

Typical syntax

In most languages, a switch statement is defined across many individual lines using one or two keywords. A typical syntax is:

• The first line contains the basic keyword, usually `switch`, `case` or `select`, followed by an expression which is often referred to as the control expression or control variable of the switch statement.
• Subsequent lines define the actual cases (the values) with corresponding sequences of statements that should be executed when a match occurs.

Each alternative begins with the particular value, or list of values (see below), that the control variable may match and which will cause the control to go to the corresponding sequence of statements. The value (or list/range of values) is usually separated from the corresponding statement sequence by a colon or an implication arrow. In many languages, every case must also be preceded by a keyword such as `case` or `when`. An optional default case is typically also allowed, specified by a `default` or `else` keyword; this is executed when none of the other cases matches the control expression.

Semantics

Semantically, there are two main forms of switch statements.

The first form are structured switches, as in Pascal, where exactly one branch is taken, and the cases are treated as separate, exclusive blocks. This functions as a generalized if–then–else conditional, here with any number of branches, not just two.

The second form are unstructured switches, as in C, where the cases are treated as labels within a single block, and the switch functions as a generalized goto. This distinction is referred to as the treatment of fallthrough, which is elaborated below.

Fallthrough

In many languages, only the matching block is executed, and then execution continues at the end of the switch statement. These include the Pascal family (Object Pascal, Modula, Oberon, Ada, etc.) as well as modern forms of Fortran and BASIC dialects influenced by Pascal, most functional languages, and many others. To allow multiple values to execute the same code (and avoid needing to duplicate code), Pascal-type languages permit any number of values per case, given as a comma-separated list, as a range, or as a combination.

Languages derived from C, and more generally those influenced by Fortran's computed GOTO, instead feature fallthrough, where control moves to the matching case, and then execution continues ("falls through") to the statements associated with the next case in the source text. This also allows multiple values to match the same point without any special syntax: they are just listed with empty bodies. Fallthrough can be prevented with a `break` keyword at the end of the matching body, which is used to go to the end of the switch, thus completing execution of the switch statement, but switch statements have default fallthrough. Syntactically, the cases are interpreted as labels, not blocks, and the switch and break statements explicitly change control flow. This can cause bugs due to unintentional fallthrough, and requires a `break` keyword at the end of each case in the common case of exclusive switches. This is thus seen by many as a language wart, and warned against in some lint tools. Some languages influenced by C, such as JavaScript, retain default fallthrough, while others remove fallthrough, or only allow it in special circumstances. Notable variations on this in the C-family include C#, in which all blocks must be terminated with a `break` unless the block is empty (i.e. fallthrough is used as a way to specify multiple values).

In some cases languages provide optional fallthrough. For example, Perl does not fall through by default, but a case may explicitly do so using a `continue` keyword. This prevents unintentional fallthrough but allows it when desired. Similarly, bash defaults to not falling through, when terminated with ;; but more recent versions allow fallthrough with ;& instead.

Compilation

Optimizing compilers such as GCC or Clang may compile a switch statement into either a branch table or a binary search through the values in the cases.[2] A branch table allows the switch statement to determine with a small, constant number of comparisons which branch to execute without having to go through a list of comparisons, while a binary search takes only a logarithmic number of comparisons, measured in the number of cases in the switch statement.

Normally, the only method of finding out if this optimization has occurred is by actually looking at the resultant assembly or machine code output that has been generated by the compiler (and is therefore seldom, if ever, done by HLL programmers).

In some languages and programming environments, the use of a `case` or `switch` statement is considered superior to an equivalent series of if else if statements because it is:

• Easier to debug (e.g. setting breakpoints on code vs. a call table, if the debugger has no conditional breakpoint capability)
• Easier to understand, and therefore
• Easier to maintain
• Fixed depth: a sequence of "if else if" statements yields deep nesting, making compilation more difficult (especially in automatically generated code)
• Faster execution potential

Additionally, an optimized implementation may execute much faster than the alternative, because it is often implemented by using an indexed branch table. For example, deciding program flow based on a single character's value, if correctly implemented, is vastly more efficient than the alternative, reducing instruction path lengths considerably. When implemented as such, a switch statement essentially becomes a perfect hash.

In terms of the control flow graph, a switch statement consists of two nodes (entrance and exit), plus one edge between them for each option. By contrast, a sequence of "if...else if...else if" statements has an additional node for every case other than the first and last, together with a corresponding edge. The resulting control flow graph for the sequences of "if"s thus has many more nodes and almost twice as many edges, with these not adding any useful information. However, the simple branches in the if statements are individually conceptually easier than the complex branch of a switch statement. In terms of cyclomatic complexity, both of these options increase it by k−1 if given k cases.

When implemented with fall-through as the default path, switch/case statements are a frequent source of bugs among even experienced programmers, given that, in practice, the "break" is almost always the desired path, but not the default behavior of the switch/case construct (at least in C and Java).

Alternative uses

Many languages evaluate expressions inside `switch` blocks at runtime, allowing a number of less obvious uses for the construction. This prohibits certain compiler optimizations, so is more common in dynamic and scripting languages where the enhanced flexibility is more important than the performance overhead.

For example, in PHP, a constant can be used as the "variable" to check against, and the first case statement which evaluates to that constant will be executed:

` switch(true) {   case (\$x == 'hello'):     foo();     break;   case (\$z == 'howdy'): break; } switch(5) {   case \$x: break;   case \$y: break; } `

This feature is also useful for checking multiple variables against one value rather than one variable against many values. COBOL also supports this form (and others forms) in the `EVALUATE` statement.

In Ruby, due to its handling of `===` equality, the statement can be used to test for variable’s class:

` case input when Array then puts 'input is an Array!' when Hash then puts 'input is a Hash!' end `

Ruby also returns a value that can be assigned to a variable, and doesn’t actually require the `case` to have any parameters (acting a bit like an `else if` statement):

` catfood =   case   when cat.age <= 1     junior   when cat.age > 10     senior   else     normal   end `

Exception handling

A number of languages implement a form of switch statement in exception handling, where if an exception is raised in a block, a separate branch is chosen, depending on the exception. In some cases a default branch, if no exception is raised, is also present. An early example is Modula-3, which use the `TRY`...`EXCEPT` syntax, where each `EXCEPT` defines a case. This is also found in Delphi, Python, Scala, and Visual Basic.NET.

Alternatives

• A series of nested if-else conditionals that examine the target one value at a time.
• A lookup table, which contains, as keys, the `case` values and, as values, the part under the `case` statement.
(In some languages, only actual data types are allowed as values in the lookup table. In other languages, it is also possible to assign functions as lookup table values, gaining the same flexibility as a real `switch` statement. See Control table article for more detail on this).
Lua does now support case/switch statements: http://lua-users.org/wiki/SwitchStatement . This lookup technique is one way to implement `switch` statements in the Lua language, which has no built-in `switch`.[3]
In some cases, lookup tables are more efficient than non-optimized `switch` statements since many languages can optimize table lookups, whereas switch statements are not optimized unless the range of values is small with few gaps. A non-optimized, non-binary search lookup, however, will almost certainly be slower than either a non-optimized switch or the equivalent multiple if-else statements.[citation needed]
• A control table (that may be implemented as a simple lookup table) can also be customized to accommodate multiple conditions on multiple inputs if required and usually exhibits greater 'visual compactness' than an equivalent switch (that can occupy many statements).
• For object-oriented programs, extensive use of polymorphism can be used.