Can anyone explain why when returning $false from a powershell function you are unable use a comparison operator to determine if the function has returned $false but when you return $true the comparison evaluates to $true?
function boolean {
return $false
}
boolean -eq $false
function boolean {
return $true
}
boolean -eq $true
>>>False
>>>True
You can work around this by setting the function call to a variable, but I was wondering if anyone could explain what is happening here under the hood?
function boolean {
return $false
}
$bool = boolean
$bool -eq $false
function boolean {
return $true
}
$bool = boolean
$bool -eq $true
>>>True
>>>True
PowerShell has two fundamental parsing modes:
argument mode, which works like traditional shells
expression mode, which works like traditional programming languages.
Running Get-help about_Parsing
provides an introduction to these modes; in short, it is the first token that determines which mode is applied.
Also note that a given statement may be composed of parts that are parsed in either mode.
boolean -eq $false
is parsed in argument mode, because its first token looks like a command name (an identifier that could be a program name, cmdlet name, function name, or alias).
Therefore, -eq
and $false
are interpreted as arguments (parameter values) to pass to function boolean
.
Since your boolean
functions are defined in a way that doesn't enforce passing values only to declared parameters, the arguments are effectively ignored, and the result of the statement is whatever the functions output ($false
or $true
).
As demonstrated in Mike Shepard's answer, you can make a function enforce use of only declared parameters (including none) with a param()
block decorated with the [CmdletBinding()]
attribute (which makes the function an advanced function), which would at least result in an error if you inadvertently passed arguments to the parameter-less boolean
function.
You can work around this by setting the function call to a variable
$bool = boolean # execute function and capture result in variable
$bool -eq $false # use variable in the comparison
The reason this works is that the -eq
statement starts with $
- a variable reference in this case - which causes PowerShell to parse in expression mode, where -eq
is recognized as an operator and $false
as its RHS.
However, there is no need for this intermediate step:
To force a piece of code to be interpreted as an expression, enclose it in (...)
, the grouping operator:
(boolean) -eq $false # Calls function 'boolean' and uses result as LHS of -eq
(...)
forces a new parsing context (which in itself is parsed in either argument or expression mode, again depending on the 1st token) and treats the result as an expression. which then allows its use as part of a larger expression, such as as an operand of the -eq
operator, or as a command argument.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With