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 search and map.
Switch statements function somewhat similarly to the
if
statement used in programming languages like C/C++, C#, Visual Basic.NET, Java and exists in most high-level imperative programming languages such as Pascal, Ada, C/C++, C#, Visual Basic.NET, 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 also offering the potential for faster execution through easier compiler optimization in many cases.
History
In his 1952 text Introduction to Metamathematics, Stephen Kleene formally proved that the CASE function is a primitive recursive function, where he defines the notiondefinition by cases
in the following manner:Kleene provides a proof of this in terms of the Boolean-like recursive functions "sign-of" sg and "not sign of" ~sg ; 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.
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, programmers write a switch statement across many individual lines using one or two keywords. A typical syntax involves:- the first
select
, followed by an expression which is often referred to as the control expression or control variable of the switch statement - subsequent lines defining the actual cases, with corresponding sequences of statements for execution when a match occurs
- In languages with fallthrough behaviour, a
break
statement typically follows acase
statement to end said statement.
case
or when
.An optional default case is typically also allowed, specified by a
default
, otherwise
, or else
keyword. This executes when none of the other cases match the control expression. In some languages, such as C, if no case matches and the default
is omitted the switch
statement simply exits. In others, like PL/I, an error is raised.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 as well as PL/I, 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, 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 language, and more generally those influenced by Fortran's computed GOTO, instead feature fallthrough, where control moves to the matching case, and then execution continues 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. Values can be special conditioned with code in the case body. In practice, fallthrough is usually prevented with a
break
keyword at the end of the matching body, which exits execution of the switch block, but this can cause bugs due to unintentional fallthrough if the programmer forgets to insert the break
statement. This is thus seen by many as a language wart, and warned against in some lint tools. Syntactically, the cases are interpreted as labels, not blocks, and the switch and break statements explicitly change control flow. 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
or return
unless the block is empty.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.An example of a switch statement that relies on fallthrough is Duff's device.
Compilation
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.A branch table allows the switch statement to determine with a small, constant number of instructions 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.
Advantages and disadvantages
In some languages and programming environments, the use of acase
or switch
statement is considered superior to an equivalent series of if else if statements because it is:- Easier to debug
- Easier for a person to read
- Easier to understand, and consequently easier to maintain
- Fixed depth: a sequence of "if else if" statements may yield deep nesting, making compilation more difficult
- Easier to verify that all values are handled. Compilers can issue a warning if some enum values are not handled.
In terms of the control flow graph, a switch statement consists of two nodes, 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.
Alternative uses
Many languages evaluate expressions insideswitch
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
switch
This feature is also useful for checking multiple variables against one value rather than one variable against many values. COBOL also supports this form in the
EVALUATE
statement. PL/I has an alternative form of the SELECT
statement where the control expression is omitted altogether and the first WHEN
that evaluates to true is executed.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 :catfood =
case
when cat.age <= 1
junior
when cat.age > 10
senior
else
normal
end
A switch statement in assembly language:
switch:
cmp ah, 00h
je a
cmp ah, 01h
je b
jmp swtend ; No cases match or "default" code here
a:
push ah
mov al, 'a'
mov ah, 0Eh
mov bh, 00h
int 10h
pop ah
jmp swtend ; Equivalent to "break"
b:
push ah
mov al, 'b'
mov ah, 0Eh
mov bh, 00h
int 10h
pop ah
jmp swtend ; Equivalent to "break"
...
swtend:
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 theTRY
...EXCEPT
syntax, where each EXCEPT
defines a case. This is also found in Delphi, Scala, and Visual Basic.NET.Alternatives
Some alternatives to switch statements can be:- A series of if-else conditionals that examine the target one value at a time. Fallthrough behavior can be achieved with a sequence of if conditionals each without the else clause.
- A lookup table, which contains, as keys, the
case
values and, as values, the part under thecase
statement. - A control table can also be customized to accommodate multiple conditions on multiple inputs if required and usually exhibits greater 'visual compactness' than an equivalent switch.
- Pattern matching, which is used to implement switch-like functionality in many functional languages.