Switch statement: Difference between revisions

Content deleted Content added
m unpiped links using script
 
(433 intermediate revisions by more than 100 users not shown)
Line 1:
{{short description|Type of selection control mechanism in computer programming languages}}
{{TOCright}}
{{more citations needed|date=April 2013}}
In [[computer programming]], a '''switch statement''' is a type of selection control [[Statement (programming)|statement]] that exists in most modern [[imperative programming]] languages (e.g., [[Pascal (programming language)|Pascal]], [[C (programming language)|C]], [[C++]], [[C Sharp (programming language)|C#]], and [[Java (programming language)|Java]]). Its purpose is to allow the value of a [[variable (programming)|variable]] or expression to control the flow of program execution via a [[Multiway branch|multiway branch]] (or "[[goto]]", one of several [[Label (programming language)|label]]s). The main reasons for using a switch include improving clarity, by reducing otherwise repetitive coding, and (if the [[heuristic]]s permit), offering the potential of faster execution through [[compiler optimization]]. In some programming languages, a statement that is syntactically different but conceptually the same as the switch statement is known as a '''case statement''', '''select statement''' or '''inspect instruction'''.
{{Use American English|date=December 2024}}
 
In [[computer programming language]]s, a '''switch statement''' is a type of selection control mechanism used to allow the value of a [[variable (programming)|variable]] or expression to change the [[control flow]] of program execution via search and map.
== History ==
In his 1952 text ''Introduction to Metamathematics'' [[Stephen Kleene]] 1952 formally proves that the CASE function (the IF-THEN-ELSE function being its simplest form) is [[primitive recursive]], where he defines the notion '''Definition by cases''' in the following manner:
:"#F. The function φ defined thus
:: φ(x<sub>1</sub> , ... , x<sub>n</sub> ) =
:::*φ<sub>1</sub>(x<sub>1</sub> , ... , x<sub>n</sub> ) if Q<sub>1</sub>(x<sub>1</sub> , ... , x<sub>n</sub> ),
:::* . . . . . . . . . . . .
:::*φ<sub>m</sub>(x<sub>1</sub> , ... , x<sub>n</sub> ) if Q<sub>m</sub>(x<sub>1</sub> , ... , x<sub>n</sub> ),
:::*φ<sub>m+1</sub>(x<sub>1</sub> , ... , x<sub>n</sub> ) otherwise,
 
Switch statements function somewhat similarly to the <code>if</code> statement used in programming languages like [[C (programming language)|C]]/[[C++]], [[C Sharp (programming language)|C#]], [[Visual Basic .NET]], [[Java (programming language)|Java]] and exist in most high-level [[imperative programming]] languages such as [[Pascal (programming language)|Pascal]], [[Ada (programming language)|Ada]], [[C (programming language)|C]]/[[C++]], [[C Sharp (programming language)|C#]],<ref name=Skeet>{{cite book |last=Skeet|first=Jon|title= C# in Depth |date=23 March 2019 |publisher= Manning |isbn= 978-1617294532}}</ref>{{rp|374–375}} [[Visual Basic .NET]], [[Java (programming language)|Java]],<ref name=Bloch>{{cite book | title= "Effective Java: Programming Language Guide" |last=Bloch| first=Joshua| publisher=Addison-Wesley | edition=third | isbn=978-0134685991| year=2018}}</ref>{{rp|157–167}} and in many other types of language, using such [[keyword (computer programming)|keyword]]s as <code>switch</code>, <code>case</code>, <code>select</code>, or <code>inspect</code>.
:where Q<sub>1</sub> , ... , Q<sub>m</sub> are mutually exclusive predicates (or φ(x<sub>1</sub> , ... , x<sub>n</sub> ) shall have the value given by the first clause which applies) is primitive recursive in φ<sub>1</sub>, ..., φ<sub>m+1</sub>, Q<sub>1</sub>, ..., Q<sub>m+1</sub>. ('''Definition by cases''')."(Kleene 1952:229)
 
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 [[heuristic]]s permit) also offering the potential for faster execution through easier [[compiler optimization]] in many cases.
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 is the same as [[Microsoft Excel]]'s "sign("cell") that returns the sign of a plus-valued cell as "1" and a minus-valued cell as "-1".
 
{|align="center"
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).
|+ '''An example of a switch statement in C'''
 
|<syntaxhighlight lang="c">
The IF-THEN-ELSE is the basis of the [[McCarthy formalism]] -- its usage replaces both [[primitive recursion]] and the [[mu-operator]].
switch (age) {
==Typical syntax==
case 1: printf("You're one."); break;
In most languages, a switch statement is defined across many individual statements. A typical syntax is:-
case 2: printf("You're two."); break;
* '''First line''' contains the actual word "'''switch'''" followed by either the name of a variable or an expression if allowed by the language's syntax. This variable or expression is usually referred to as the "control variable" of the switch statement.
case 3: printf("You're three.");
* '''subsequent lines''' define one or more blocks of code that represent possible branches that program execution may take.
case 4: printf("You're three or four."); break;
 
default: printf("You're not 1, 2, 3 or 4!");
Each alternative block of code begins with a line containing the '''case''' keyword followed by a value that the control variable may have. If the value of the control variable matches this value, program execution will [[goto|jump]] to the beginning of that block of code (which is simply a [[Label (programming language)|program label]] within the current procedure). If not, the value specified in the next block (if present) is examined and the process repeats.
 
An optional special block is also allowed, which does not specify any value and which begins with the '''default''' keyword instead of the '''case''' keyword. If this block is present and, if none of the values listed for any other block matches that of the control variable, program execution will jump to the statement following the '''default''' keyword.
 
The method of terminating a block is also of note. Typically, a '''break''' keyword is used to signal (i.e. [[goto]]) the end of the block. When encountered, this keyword causes program execution to continue with the first statement after the series of statements within the switch statement, thus completing execution of the switch statement. It is equivalent to a '[[goto]] the end of the series of case statement blocks'. If no break keyword is present at the end of the block, in many languages program execution "falls through" to the code associated with the next block in the switch statement, as if its value also matched the value of the control variable. Notable exceptions include [[C Sharp (programming language)|C#]], in which fallthrough is not permitted unless the block is empty and all blocks must be terminated via a '''break''', or by using another keyword. Similarly, almost all [[BASIC]] dialects that feature this type of statement do not allow fallthrough.
 
== Compilation ==
If the range of input values is identifiably 'small' and has only a few gaps, some compilers that incorporate an [[Optimization (computer science)|optimizer]] may actually implement the switch statement as a [[branch table]] or an array of indexed [[function pointer]]s instead of a lengthy series of conditional instructions - which can be very much faster.
 
====Optimized switch====
It is probably true to say, however, that many programmers do not realize how extremely important it is to obtain a very compact range of possible values for optimization to actually occur within the switch statement<ref>http://www.rmbconsulting.us/Publications/PointerToFunction.pdf</ref>. They assume, incorrectly, that simply using a switch statement in their program is inherently efficient. It may indeed be true that the code is much neater and easier to maintain - but it is certainly not necessarily always optimized for faster execution unless the values are strictly suitable. Sometimes they have to be converted first by the programmer to a more suitable range using a simple transformation (complex/lengthy transformations may defeat the purpose so should be avoided).
See [[algorithmic efficiency]] for an explanation of how the programmer can "assist" the compiler to make an efficient choice.
See also the section 'Compiler generated branch tables' in [[branch table]] article for why optimization is not always performed as expected and how to solve this.
 
====Checking for optimization====
Normally, the only method of finding out if this optimization has occurred is by actually looking at the resultant [[assembler (computer programming)|assembler]] or [[machine code]] output that has been generated by the compiler (and is therefore seldom, if ever, done by [[High-level programming language|HLL]] programmers).
The first 'C' example below would be eligible for this kind of optimization if the compiler supported it (the range '0' thru '9' with zero gaps without a defined case label).
 
== Advantages==
 
In some languages and programming environments, the use of a '''case''' or '''switch''' statement is considered superior to an equivalent series of ''if-else'' 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 read''' (subjective)
* '''easier to understand''' and therefore
* '''easier to maintain'''
 
Additionally, as mentioned above, an [[Optimization (computer science)|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 length]]s considerably.
 
==Disadvantages==
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).
 
==Examples==
The following are simple examples, written in the various languages, that use switch (or switch-like) statements to print one of several possible lines, depending on the value of an integer entered by the user.
 
===C, C++, Java, php, ActionScript===
In [[C (programming language)|C]] and similarly-constructed languages, the lack of '''break''' keywords to cause fall through of program execution from one block to the next is used extensively. For example, if n=2, the fourth case statement will produce a match to the control variable. The next line outputs "n is an even number.". As an apparent bug, execution continues through the next 3 case statements and to the next line, which outputs "n is a prime number." which is a common error due to a missing '''break''' statement. The '''break''' line after a case block causes the switch statement to conclude. If the user types in more than one digit, the '''default''' block is executed, producing an error message by executing the '''default''' code.
 
<source lang="c">
switch (n) {
case 0:
puts("You typed zero.");
break;
case 1:
case 9:
puts("n is a perfect square.");
break;
case 2:
puts("n is an even number.");
case 3:
case 5:
case 7:
puts("n is a prime number.");
break;
case 4:
puts("n is a perfect square.");
case 6:
case 8:
puts("n is an even number.");
break;
default:
puts("Only single-digit numbers are allowed.");
break;
}
</syntaxhighlight>
</source>
|}
 
===Pascal= History ==
[[Pascal_(programming_language)|Pascal]] doesn’t have the “fall through” mechanism; it uses '''case''' instead of '''switch''', and '''else''' instead of '''default'''.
<source lang="pascal">
case place of
1: writeln('Champion');
2: writeln('First runner-up');
3: writeln('Second runner-up');
else writeln('Work hard next time!');
end;
</source>
 
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:
===Perl===
[[Perl]] 5.10 (backported from [[Perl 6]]) has a powerful builtin switch statement called <tt>given</tt>, where the cases are called <tt>when</tt>:
 
{{blockquote|text=
<source lang="perl">
"#F. The function φ defined thus
use feature 'switch';
: φ(x<sub>1</sub> , ... , x<sub>n</sub> ) =
given ($foo) {
::*φ<sub>1</sub>(x<sub>1</sub> , ... , x<sub>n</sub> ) if Q<sub>1</sub>(x<sub>1</sub> , ... , x<sub>n</sub> ),
when (undef) {
::* . . . . say '$foo. is undefined';. . . . . . .
::*φ<sub>m</sub>(x<sub>1</sub> , ... , x<sub>n</sub> ) if Q<sub>m</sub>(x<sub>1</sub> , ... , x<sub>n</sub> ),
}
::*φ<sub>m+1</sub>(x<sub>1</sub> , ... , x<sub>n</sub> ) otherwise,
when ("foo") {
say '$foo is the string "foo"';
}
when ([1,3,5,7,9]) {
say '$foo is an odd digit';
continue; # Fall through
}
when ($_ < 100) {
say '$foo is numerically less than 100';
}
when (\&complicated_check) {
say 'a complicated check for $foo is true';
}
default {
die "I don't know what to do with $foo";
}
}
</source>
 
where Q<sub>1</sub> , ... , Q<sub>m</sub> are mutually exclusive predicates (or φ(x<sub>1</sub> , ... , x<sub>n</sub>) shall have the value given by the first clause which applies) is primitive recursive in φ<sub>1</sub>, ..., φ<sub>m+1</sub>, Q<sub>1</sub>, ..., Q<sub>m+1</sub>.|author=Stephen Kleene|source=<ref>"Definition by cases", Kleene 1952:229</ref>}}
===Python===
[[Python (programming language)|Python]] does not have direct language support for the switch statement. However, it is possible to emulate this behaviour, through a [[Associative_array|dictionary]] of functions.
 
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.
Here is an example that does not use a “fall through” mechanism; a function per case is needed, and hashing is used to determine which function is called. The default case is mimicked by using dict.get()'s fallback parameter:
 
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).
<source lang="python">
switch = {
0 : TypedZeroFunc,
1 : PerfectSquareFunc,
2 : PrimeNumberFunc,
3 : PrimeNumberFunc,
4 : PerfectSquareFunc
}
 
The IF-THEN-ELSE is the basis of the [[McCarthy formalism]]: its usage replaces both primitive recursion and the [[mu-operator]].
switch.get(n, DefaultFunc)() # Switch based on value of n.
</source>
 
The earliest [[Fortran]] compilers supported the [[Goto#Computed_GOTO_and_Assigned_GOTO|computed GOTO]] statement for multi-way branching. Early [[ALGOL]] compilers supported a SWITCH data type which contains a list of "designational expressions". A GOTO statement could reference a switch variable and, by providing an index, branch to the desired destination. With experience it was realized that a more formal multi-way construct, with single point of entrance and exit, was needed. Languages such as [[BCPL]], [[ALGOL-W]], and [[ALGOL-68]] introduced forms of this construct which have survived through modern languages.
===Ruby===
[[Ruby (programming language)|Ruby]] doesn’t have the “fall through” mechanism; it also uses '''case''' instead of '''switch''', '''when''' instead of '''case''' and '''else''' instead of '''default'''.
 
== Typical syntax ==
<source lang="ruby">
case n
when 0
puts 'You typed zero'
when 1, 9
puts 'n is a perfect square'
when 2
puts 'n is a prime number'
puts 'n is an even number'
when 3, 5, 7
puts 'n is a prime number'
when 4, 6, 8
puts 'n is an even number'
else
puts 'Only single-digit numbers are allowed'
end
</source>
 
In most languages, programmers write a switch statement across many individual lines using one or two keywords. A typical syntax involves:
Also can be used to asign a value, in a more compact way:
 
* the first <code>select</code>, followed by an expression which is often referred to as the ''control expression'' or ''control variable'' of the switch statement
<source lang="ruby">
* subsequent lines defining the actual cases (the values), with corresponding sequences of statements for execution when a match occurs
result = case n
* In languages with fallthrough behavior, a <code>break</code> statement typically follows a <code>case</code> statement to end said statement. [Wells]
when 0 then 'none'
* In some languages, e.g., [[PL/I]], the control expression is optional; if there is no control expression then each alternative begins with a <code>WHEN</code> clause containing a Boolean expression and a match occurs for the first case for which that expression evaluates to true. This usage is similar to the if/then/elseif/else structures in some other languages, e.g., [[Perl]].
when 1..9 then 'valid'
* In some languages, e.g., [[Rexx]], no control expression is allowed and each alternative begins with a <code>WHEN</code> clause containing a Boolean expression and a match occurs for the first case for which that expression evaluates to true.
else 'too much'
end
puts 'n is ' + result
</source>
 
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 [[goto]] the corresponding sequence of statements. The value (or list/range of values) is usually separated from the corresponding statement sequence by a colon or by an implication arrow. In many languages, every case must also be preceded by a keyword such as <code>case</code> or <code>when</code>.
===Ada===
[[Ada (programming language)|Ada]] doesn’t have the “fall through” mechanism; it also uses '''case''' instead of '''switch''', '''when''' instead of '''case''' and '''others''' instead of '''default'''. In addition,
Ada requires full coverage of all possible values for the type in the case statement. If a when others =>
case is not specified, then the code will not compile if either extra cases are specified, or missing.
If at some point in the future, the definition of Digit is modified, the compiler will ensure that the programmer updates the case statement to reflect the changes to the type definition, which ensures that the program is kept up to date and helps to reduce maintenance costs.
A list of values for a particular case can be combined using '|' as shown below, or a range of values
may be specified using ".." to indicate the extents of the range. e.g, when 0 .. 4 => Put_Line ("Small Digits);
In the example below, there is no need to check for values outside the range of 0 to 9 because the type is guaranteed to have a value within the range for the type.
 
An optional default case is typically also allowed, specified by a <code>default</code>, <code>otherwise</code>, or <code>else</code> 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 <code>default</code> is omitted the <code>switch</code> statement simply does nothing. In others, like PL/I, an error is raised.
<source lang="ada">
type Digit is new Integer range 0 .. 9;
n : Digit;
...
case n is
when 0 =>
Put_Line ("You typed zero");
when 1 | 9 =>
Put_Line ("n is a perfect square");
when 3 | 5 | 7 =>
Put_Line ("n is a prime number");
when 4 =>
Put_Line ("n is a perfect square");
Put_Line ("n is an even number");
when 6 | 8 =>
Put_Line ("n is an even number");
end case;
</source>
 
===Eiffel= Semantics ==
[[Eiffel (programming language)|Eiffel]]'s multi-branch instruction uses '''inspect''', '''when''', and '''else''' versus the '''switch''', '''case''', and '''default''' of C. It does not have “fall through” behavior. Also, the '''else''' part is optional. However, an omitted '''else''' differs from an included, but empty '''else'''. If the '''else''' is empty and a case is processed that is not specified in one of the '''when''' parts, control passes through the '''else'''. But if the '''else''' is omitted, it is assumed that all cases should be identified in a '''when''' part. In this case an exception will occur as a result of processing a case not handled in a '''when''' part.
 
Semantically, there are two main forms of switch statements.
<source lang="eiffel">
inspect
n
when 0 then
print ("You typed zero%N")
when 1, 9 then
print ("n is a perfect square%N")
when 2 then
print ("n is a prime number%N")
print ("n is an even number%N")
when 3, 5, 7 then
print ("n is a prime number%N")
when 4 then
print ("n is a perfect square%N")
print ("n is an even number%N")
when 6, 8 then
print ("n is an even number%N")
else
print ("Only single digit numbers are allowed%N")
end
</source>
 
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 (computer programming)|conditional]], here with any number of branches, not just two.
===Haskell===
 
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.
[[Haskell programming language|Haskell]]'s '''case''' construct, unlike C-influenced languages, has no fall-through behaviour. It is an [[expression (programming)|expression]] which returns a value, and it can [[deconstruct]] values using [[pattern matching]].
 
=== Fallthrough ===
<source lang="haskell">
case list of
(f:r) -> "Not empty, first item is " ++ show f
[] -> "List is empty!"
</source>
 
In many languages, only the matching block is executed, and then execution continues at the end of the switch statement. These include the [[Pascal (programming language)|Pascal]] family (Object Pascal, Modula, Oberon, Ada, etc.) 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 (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.
===OCaml, F#===
 
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 ("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. Values can be [[special condition]]ed with code in the case body. In practice, fallthrough is usually prevented with a <code>break</code> 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 <code>break</code> statement. This is thus seen by many<ref>van der Linden, Peter (1994). ''Expert C Programming: Deep C Secrets'', p. 38. Prentice Hall, Eaglewood Cliffs. {{ISBN|0131774298}}.</ref> as a language wart, and warned against in some [[lint tool]]s. 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 Sharp (programming language)|C#]], in which all blocks must be terminated with a <code>break</code> or <code>return</code> unless the block is empty (i.e. fallthrough is used as a way to specify multiple values).
[[OCaml]] and [[F Sharp (programming language)|F#]]'s '''match''' construct is like Haskell's <tt>case</tt> above.
 
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 <code>continue</code> keyword. This prevents unintentional fallthrough but allows it when desired. Similarly, [[Bash (Unix shell)|Bash]] defaults to not falling through when terminated with <code>;;</code>, but allows fallthrough<ref>since [http://git.savannah.gnu.org/cgit/bash.git/tree/NEWS?id=3185942a5234e26ab13fa02f9c51d340cec514f8#n111 version 4.0], released in 2009.</ref> with <code>;&</code> or <code>;;&</code> instead.
<source lang="ocaml">
(* OCaml *)
match list with
f::r -> "Not empty, first item is " ^ string_of_int f
| [] -> "List is empty!"
</source>
 
An example of a switch statement that relies on fallthrough is [[Duff's device]].
<source lang="ocaml">
// F#
match list with
| f::r -> "Not empty, first item is " + string f
| [] -> "List is empty!"
</source>
 
===Bash= Compilation ==
[[Bash]] and other scripting languages offer a case construct using the OR operator, |, to separate the selections, and the ) symbol to separate the list of selections from the action to be taken.
<source lang="bash">
case $n in
0) echo 'You typed 0.';;
1|9) echo "$n is a perfect square.";;
3|5|7) echo "$n is a prime number.";;
4) echo "$n is a perfect square.
$n is an even number";;
2|6|8) echo "$n is an even number.";;
*) echo 'Only single-digit numbers are allowed.';;
esac
</source>
 
[[Optimizing compiler]]s such as [[GNU Compiler Collection|GCC]] or [[Clang]] may compile a switch statement into either a [[branch table]] or a [[binary search]] through the values in the cases.<ref>Vlad Lazarenko. [https://web.archive.org/web/20220313040503/http://lazarenko.me/switch/ From Switch Statement Down to Machine Code]</ref>
===Windows PowerShell===
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.
[[Windows PowerShell]] employs a construct whereby the action to be taken is enclosed in a scriptblock (i.e. curly braces), with the selector placed directly before it. The selector can consist of regular expressions if the "-[[regex]]" parameter is inserted after the "switch" command; similarly, wildcards are supported using the "-wildcard" parameter. In either case, the wildcard or regex must be enclosed in quote marks.<ref>{{cite web
|url=http://www.microsoft.com/technet/scriptcenter/resources/pstips/jan08/pstip0111.mspx
|title=Windows PowerShell Tip of the Week
|date=January 2008
|accessdate=2009-04-28
|publisher=Microsoft
}}</ref>
 
Normally, the only method of finding out if this optimization has occurred is by actually looking at the resultant [[Assembly language|assembly]] or [[machine code]] output that has been generated by the compiler.
This much 'more powerful' Powershell implementation unfortunately comes with the strong likelihood that significant efficiency gains, expected with a less complex switch statement, may not be realizable via an efficient [[branch table]] - usually generated by an optimizing compiler. This is partly because of the inherent [[parsing]] [[overhead (computing)|overhead]] (especially if the "regex" option is used), but also because the range of permissable logical expressions and value ranges is not so well constrained.
 
== Advantages and disadvantages ==
Unlike C-based implementations, if a "break" statement is not included at the end of a scriptblock, the switch statement will continue to test each case and execute further scriptblocks.
In some languages and programming environments, the use of a <code>case</code> or <code>switch</code> statement is considered superior to an equivalent series of ''if [[else if]]'' statements because it is:
<source lang="powershell">
switch (n)
{
0 { Write-Host 'You typed 0' }
{ ($_ -eq 1) -or ($_ -eq 4) -or ($_ -eq 9) }
{ Write-Host 'n is a perfect square' }
{ (($_ % 2) -eq 0) -and ($_ -ne 0) }
{ Write-Host 'n is an even number' }
{ ($_ -eq 2) -or ($_ -eq 3) -or ($_ -eq 5) -or ($_ -eq 7) }
{ Write-Host 'n is an prime number' }
default { Write-Host 'Only single-digit numbers are allowed' }
}
</source>
 
* Easier to debug (e.g. setting breakpoints on code vs. a call table, if the debugger has no conditional breakpoint capability)
===Visual Basic .NET ===
* Easier for a person to read
In [[Visual Basic .NET]], the switch statement is called "Select Case", and fall-through to later blocks is not supported.
* Easier to understand, and consequently easier to maintain
<source lang="vb">
* Fixed depth: a sequence of "if else if" statements may yield deep nesting, making compilation more difficult (especially in automatically generated code)
Select Case n
* Easier to verify that all values are handled. Compilers can issue a warning if some enum values are not handled.
Case 0
MsgBox "n is 0"
Case 2, 4, 6, 8
MsgBox "n is even"
Case 1, 3, 5, 7, 9
MsgBox "n is odd"
Case Else
MsgBox "only positive single-digit numbers are allowed.", vbCritical
End Select
</source>
 
Additionally, an [[optimization (computer science)|optimized]] implementation may execute much faster than the alternative, because it is often implemented by using an indexed [[branch table]].<ref>{{cite book |last1=Guntheroth |first1=Kurt |title=Optimized C++ |date=April 27, 2016 |publisher=O'Reilly Media |isbn=9781491922033 |page=182}}</ref> 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 length]]s considerably. When implemented as such, a switch statement essentially becomes a [[perfect hash]].
===Visual Basic (classic), VBA, VB Script ===
In [[Visual Basic]], the switch statement is called "Select Case", and fall-through to later blocks is not supported. [[Short-circuit evaluation]] is used.
<source lang="vb">
Select Case n
Case "s"
MsgBox "Case values of any type are supported"
Case "s"
MsgBox "This block is not an error but will never be selected"
Case ArbitraryFunction()
MsgBox "Any Expression which can be evaluated at runtime may be used as a case value or selector"
Case 2+3: MsgBox "The colon is a general language feature, not a part of the switch statement"
MsgBox "Each block is terminated by the following Case or End statement"
Case Else
MsgBox "Case values which do not match the selector type will cause an exception", vbCritical
End Select
</source>
 
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.
===WebDNA===
[[WebDNA]] example is easy to understand:
<source lang="cfm">
[text]x=5[/text]
 
== Case and Switch expressions==
[switch value=[x]]
[case value=1]
The value of x was 1
[/case]
[case value=2]
The value of x was 2
[/case]
[default]
The value of x was neither 1 nor 2; it was [x]
[/default]
[/switch]
</source>
 
''Case expressions'' are supported by languages dating at least as far back as [[ALGOL-W]].<ref name="Wirth">{{cite journal |last1=Wirth |first1=Niklaus |author1-link=Niklaus Wirth |last2=Hoare |first2=C. A. R. |author2-link=Tony Hoare |date=June 1966 |title=A contribution to the development of ALGOL |url=https://dl.acm.org/doi/10.1145/365696.365702 |journal=Communications of the ACM |volume=9 |issue=6 |pages=413–432 |doi=10.1145/365696.365702 |s2cid=11901135 |via=[[Association for Computing Machinery]] |access-date=2020-10-07|doi-access=free }}</ref> In ALGOL-W, an integer expression was evaluated, which then evaluated the desired expression from a list of expressions:
===Visual Foxpro===
<syntaxhighlight lang="pascal">
[[Visual FoxPro]]:
J := case I of (3.14, 2.78, 448.9);
<source lang="visualfoxpro">
A := case DECODE(C)-128 of ("A", "B", "C", "D", "E", "F");
Do Case
</syntaxhighlight>
Case field_1 = "Z"
Replace field_b With 1
Case field_1 = "Y"
Replace field_b With 2
Case field_1 = "Z"
Replace field_b With 3
Endcase
</source>
 
Other languages supporting case expressions include [[SQL]], [[Standard ML]], [[Haskell]], and [[Common LISP]].
==Symbolic constants==
In many (but not all) circumstances,
using names rather than ordinary integers makes
the source code easier to read. This has no influence
on the behavior of the program.
This style of switch statement is commonly
used for [[finite state machine]] implementation.
The tradition in C is for such constants to be in all capitals,
although this is not enforced by the compiler. Java and COBOL have equivalent capabilities.
Here are some examples:
 
''Switch expressions'' are introduced in [[Java version history#Java SE 12|Java SE 12]], 19 March 2019, as a preview feature. Here a whole switch expression can be used to return a value. There is also a new form of case label, {{code|case L-> }} where the right-hand-side is a single expression. This also prevents fall through and requires that cases are exhaustive. In Java SE 13 the <code>yield</code> statement is introduced, and in Java SE 14 switch expressions become a standard language feature.<ref>{{cite web|access-date=2021-04-28|title=JEP 325: Switch Expressions (Preview)|url=https://openjdk.java.net/jeps/325|website=openjdk.java.net}}</ref><ref>{{cite web|access-date=2021-04-28|title=JEP 354: Switch Expressions (Second Preview)|url=https://openjdk.java.net/jeps/354|website=openjdk.java.net}}</ref><ref>{{cite web|access-date=2021-04-28|title=JEP 361: Switch Expressions|url=https://openjdk.java.net/jeps/361|website=openjdk.java.net}}</ref> For example:
===C (using enum)===
<sourcesyntaxhighlight lang="cjava">
int ndays = switch (month) {
enum
case JAN, MAR, MAY, JUL, AUG, OCT, DEC -> 31;
{
case APR, JUN, SEP, NOV -> 30;
STATE_READY = 1,
case FEB -> {
STATE_SET = 2,
if (year % 400 == 0) yield 29;
STATE_GO = 3,
else if (year % 100 == 0) yield 28;
STATE_FAIL = 4
else if (year % 4 == 0) yield 29;
else yield 28; }
};
</syntaxhighlight>
switch( state )
{
case STATE_READY:
state = STATE_SET;
if( x < 0 ) state = STATE_FAIL;
break;
case STATE_SET:
state = STATE_GO;
if( y > 0 ) state = STATE_FAIL;
break;
case STATE_GO:
printf( "go!\n" );
break;
case STATE_FAIL:
exit( -1 );
}
</source>
 
== Alternative uses ==
Many languages evaluate expressions inside <code>switch</code> 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.
 
=== PHP ===
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:
<sourcesyntaxhighlight lang="php">
switch (true) {
case ($x == 'hello'):
foo();
break;
case ($z == 'howdy'): break;
}
switch (5) {
case $x: break;
case $y: break;
}
</syntaxhighlight>
</source>
 
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 othersother forms) in the <code>EVALUATE</code> statement. PL/I has an alternative form of the <code>SELECT</code> statement where the control expression is omitted altogether and the first <code>WHEN</code> that evaluates to ''true'' is executed.
 
=== Ruby ===
In [[Ruby]], due to its handling of <code>===</code> equality, the statement can be used to test for variable’s class:
In [[Ruby (programming language)|Ruby]], due to its handling of <code>===</code> equality, the statement can be used to test for variable’s class:
 
<sourcesyntaxhighlight lang="ruby">
case input
when Array: then puts 'input is an Array!'
when Hash: then puts 'input is a Hash!'
end
</syntaxhighlight>
</source>
 
Ruby also returns a value that can be assigned to a variable, and doesn’t actually require the <code>case</code> to have any parameters (acting a bit like an <code>else if</code> statement):
 
<sourcesyntaxhighlight lang="ruby">
catfood =
case
when cat.age <= 1:
junior
when cat.age > 10:
senior
else
else normal
endnormal
end</syntaxhighlight>
</source>
 
=== Assembler ===
A switch statement in [[assembly language]]:
<syntaxhighlight lang="nasm">
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:
</syntaxhighlight>
 
=== Python ===
 
For Python 3.10.6, [[Python Enhancement Proposal|PEPs]] 634-636 were accepted, which added {{code|lang=python|match}} and {{code|lang=python|case}} keywords.<ref>{{Cite web |last=Galindo Salgado |first=Pablo |title=What's New In Python 3.10 |url=https://docs.python.org/3/whatsnew/3.10.html |access-date=2022-08-19 |website=Python 3.10.6 documentation}}</ref><ref>{{Cite web |last1=Bucher |first1=Brandt |last2=van Rossum |first2=Guido |author-link2=Guido van Rossum |date=2020-09-12 |title=PEP 634 – Structural Pattern Matching: Specification |url=https://peps.python.org/pep-0634/ |access-date=2022-08-19 |website=Python Enhancement Proposals}}</ref><ref>{{Cite web |last1=Kohn |first1=Tobias |author-link=Guido van Rossum |last2=van Rossum |first2=Guido |date=2020-09-12 |title=PEP 635 – Structural Pattern Matching: Motivation and Rationale |url=https://peps.python.org/pep-0635/ |access-date=2022-08-19 |website=Python Enhancement Proposals}}</ref><ref>{{Cite web |last=Moisset |first=Daniel F |title=PEP 636 – Structural Pattern Matching: Tutorial |url=https://peps.python.org/pep-0636/ |access-date=2022-08-19 |website=Python Enhancement Proposals}}</ref> Unlike other languages, Python notably doesn't exhibit fallthrough behavior.
<syntaxhighlight lang="python" line>
letter = input("Put in a single letter: ").strip()[0].casefold() # First non-whitespace character of the input, lowercase
match letter:
case "a" | "e" | "i" | "o" | "u": # Unlike conditions in if statements, the `or` keyword cannot be used here to differentiate between cases
print(f"Letter {letter} is a vowel!")
case "y":
print(f"Letter {letter} may be a vowel.")
case _: # `case _` is equivalent to `default` from C and others
print(f"Letter {letter} is not a vowel!")
</syntaxhighlight>
 
=== 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 <code>TRY</code>...<code>EXCEPT</code> syntax, where each <code>EXCEPT</code> defines a case. This is also found in [[Delphi (programming language)|Delphi]], [[Scala (programming language)|Scala]], and [[Visual Basic .NET]].
 
== Alternatives ==
 
* A [[lookup table]], which contains, as keys, the '''case''' values and, as values, the part under the '''case''' statement.
Some alternatives to switch statements can be:
::(In some languages, only actual data types are allowed as values in the lookup table. In other languages, it is also possible to assign [[Function (computer science)|functions]] as lookup table values, gaining the same flexibility as a real '''switch''' statement. See [[Control table]] article for more detail on this).
 
::This lookup technique is one way to implement '''switch''' statements in the [[Lua (programming language)|Lua]] language - which has no built-in '''switch''' <ref>[http://lua-users.org/wiki/SwitchStatement Switch statement in Lua]</ref>.
* A series of ''if-else'' [[Conditional (programming)|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.
::In some cases, lookup tables are more efficient than non-[[Program optimization|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-[[Program optimization|optimized]], non-[[binary search]] lookup, however, will almost certainly be slower than either a non-optimized switch or the equivalent multiple ''if-else'' statements.
* A [[lookup table]], which contains, as keys, the <code>case</code> values and, as values, the part under the <code>case</code> statement.
* A [[Control table]] (that may be implented 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).
::(In some languages, only actual data types are allowed as values in the lookup table. In other languages, it is also possible to assign [[Function (computer science)|functions]] as lookup table values, gaining the same flexibility as a real <code>switch</code> statement. See [[Control table]] article for more detail on this).
* For [[Object-oriented programming|Object-oriented programs]], extensive use of [[Type polymorphism|polymorphism]] can be used
::[[Lua]] does not support case/switch statements.<ref name="lua"/> This lookup technique is one way to implement <code>switch</code> statements in the Lua language, which has no built-in <code>switch</code>.<ref name="lua">[http://lua-users.org/wiki/SwitchStatement Switch statement in Lua]</ref>
::In some cases, lookup tables are more efficient than non-[[Program optimization|optimized]] <code>switch</code> 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|date=October 2011}}
* 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).
* [[Pattern matching]], which is used to implement switch-like functionality in many [[functional programming|functional]] languages.
 
== See also ==
 
*[[Algorithmic efficiency]] - general discussion on improving speed of [[algorithm]]s
* [[Algorithmic efficiency]]
*[[Branch table]] - an extremely fast, optimized form of a switch statement used mostly in[[Assembler language]]s and [[compiler]]s
* [[Branch table]]
*[[Control table]] - a customizable switch-like [[array]] [[data structure]], requiring an[[interpreter (computing)|interpreter]]
* [[Control table]]
*[[Duff's device]] - a [[loop unwinding]] technique that makes use of a switch statement.
* [[Duff's device]]
*[[Conditional (programming)|Conditional statement]] - A switch statement is a type of conditional statement
* [[Index mapping]]
*[[McCarthy Formalism]] - for history and historical references
 
*[[Multiway branch]] - a switch statement is a type of multiway branch
== References ==
 
{{reflist}}
* [[Stephen Kleene]], 1952 (10th reprint 1991), ''Introduction to Metamathematics'', North-Holland Publishing Company, Amsterdam NY, ISBN: 0 7204 2103 9
* [[ George Boolos]], [[John Burgess]], and [[Richard Jeffrey]], 2002, ''Computability and Logic: Fourth Edition'', Cambridge University Press, Cambridge UK, ISBN 0521 00758 5 paperback. cf page 74-75.
 
== Further reading ==
==External links==
 
[http://www.safercode.com/blog/2008/10/28/optimizing-switch-case-statements-in-c-for-speed.html Optimizing Switch-Case Statements In C For Speed]
* [[Stephen Kleene]], 1952 (10th reprint 1991), ''Introduction to Metamathematics'', North-Holland Publishing Company, Amsterdam NL, {{ISBN|0-7204-2103-9}}
<!--Please see this URL before adding external links here: http://meta.wikimedia.org/wiki/When_should_I_link_externally -->
* [[George Boolos]], [[John P. Burgess|John Burgess]], and [[Richard Jeffrey]], 2002, ''Computability and Logic: Fourth Edition'', Cambridge University Press, Cambridge UK, {{ISBN|0-521-00758-5}} paperback. cf page 74-75.
 
[[Category:Conditional constructs]]
 
[[ru:Оператор ветвления#Переключатель (оператор множественного выбора)]]
[[da:Switch udsagn]]
[[es:Switch case]]
[[fr:Switch (instruction)]]
[[hr:Switch naredba]]
[[is:Switch-setning]]
[[ja:Switch文]]
[[pl:Instrukcja wyboru]]