$UserChoice = Read-Host "Enter # of tool you want to run"
switch -exact ($UserChoice) {
1 {Write-Host 'You selected 1'}
1a {Write-Host 'You selected 1a'}
1b {Write-Host 'You selected 1b'}
1c {Write-Host 'You selected 1c'}
1d {Write-Host 'You selected 1d'}
}
Preface: I know the fix is to put the comparison values in quotes, ex: '1d'
. I want to know WHY PowerShell is acting the way it is for learning sake.
- If I enter 1b at prompt, it returns 1b whereas if I enter 1d it returns nothing, why?
- If I enter 1b at prompt, it returns 1b whereas if I enter 1 it returns 1 and 1d, why?
- It seems PowerShell is interpreting d in a switch statement comparison value different for some reason, why?
--EDIT: I just noticed VISUALLY the comparison values are different colors (1 & 1d are darker) so I guess PowerShell ISE syntax highlighting is telling us they're being treated differently. 4. What do the colors mean (maroon/dark-RedOrPurple VS purple?
CodePudding user response:
Before explaining why the 1d
label is "special", I should note that the -exact
mode (which is the default mode of comparison for a switch
statement) is probably a bit misleading.
It simply means "use the -eq
operator to compare input values to case labels".
The reason 1d
behaves differently is that PowerShell doesn't recognize the expression 1d
as a string. Instead, it interprets d
is a numerical suffix signifying the [decimal]
type, and the case label value is thus the same as if you'd written 1.0
or $([decimal]1)
.
The result is that comparison to the input string "1"
comes out the same for both - "1" -eq 1
and "1" -eq 1d
are both true, thanks to PowerShell's overloaded operators.
If you ever expand your options further, you'll encounter the same problem with 1l
(l
= [long]
), and, if using PowerShell 7, eventually 1n
, 1s
, 1u
, and 1y
.
Quote the switch labels to avoid PowerShell parsing them as a numerical expressions:
$UserChoice = Read-Host "Enter # of tool you want to run"
switch -exact ($UserChoice) {
'1' {Write-Host 'You selected 1'}
'1a' {Write-Host 'You selected 1a'}
'1b' {Write-Host 'You selected 1b'}
'1c' {Write-Host 'You selected 1c'}
'1d' {Write-Host 'You selected 1d'}
}
See the about_Numeric_Literals help topic for a more comprehensive overview of suffixes interpreted as numerical modfiers by PowerShell.
CodePudding user response:
To add to Mathias' excellent answer:
The
switch
statement's branch conditionals should never have allowed the use of barewords (unquoted tokens serving as strings).It amounts to an inappropriate blending of PowerShell's two fundamental parsing modes, argument mode and expression mode.
- In expression mode - which is the appropriate one to apply - strings must be quoted; e.g., to match a string with verbatim value
1d
, it must be represented as'1d'
, which disambiguates it from the number literal1d
, a[decimal]
.
- In expression mode - which is the appropriate one to apply - strings must be quoted; e.g., to match a string with verbatim value
See GitHub issue #3668 for a discussion.
The
-exact
switch opts into the default behavior and, given the non-exact nature of this behavior, is confusingly named.- GitHub issue #8599 therefore suggests (soft-)deprecating it.