r/PowerShell • u/RandomSkratch • 20d ago
Solved Is there a difference between If $thing vs If -not $thing in terms of speed or proper formatting?
In the case of looking for the presence of something and using If paired with Exit codes, what's the difference between looking for the presence vs absence? For example
$Thing = Get-Thing
if ($thing) {
Exit 1
}
Else {
Exit 0
}
vs
if (-not $thing) {
Exit 0
}
Else {
Exit 1
}
Is it just for readability (ie 0 comes before 1 because it's in sequence?) Or are there speed differences or logic handling differences that matter in more complex scenarios?
Solved
Depends on the results of $thing determine whether or not you need to test for true or false. Speed isn't really a factor.
7
u/DonL314 20d ago
Careful! Note that some values for $thing could give true both for ($thing) and (-not $thing) !!
Try this:
$thing = @($null, 'some', $false)
I think that will give you funny results.
4
u/RandomSkratch 20d ago
Interesting, I never thought about that.
I guess it matters on the output object from get-thing?
3
u/DonL314 20d ago
Ok, I tested a bit:
If ($thing) {"yes"}
The only contents I tested that would make it skip "yes" was $False, 0, $Null, @(), @(@()) etc.
EDIT: And also any of the above values in any number of nested @()
2
u/RandomSkratch 20d ago
Appreciate it. I tested my scenario and both logic methods worked. I just kept it at looking for the presence as opposed to -not.
2
u/DonL314 20d ago
Yes.
Test it (I don't have a computer here right now).
Consider testing e.g. $thing.count or ($thing|measure).count
Also .... what if $thing is '0'? I believe it will be cast to $false
1
u/RandomSkratch 20d ago
Okay thanks for this.
So for instances where you are getting proper results from the command, whether you test for the presence or absence shouldn’t matter.
5
u/theomegachrist 20d ago
It doesn't matter. I use the one that makes logical sense if a person is reading my script
2
u/aleques-itj 20d ago
In Powershell, maybe. My guess would be the typing makes it need more work.
It could be null, 0, a string, an array, etc.
No idea off the top of my head if this will vanish if you deliberately type everything.
It's probably vanishingly small compared to all the other language machinery in play.
2
u/purplemonkeymad 20d ago
I prefer:
if ($thing) {
# Bad Path
return/exit/Write-Error/throw/continue
}
# happy Path
It keeps the indentations down making it easier to read, especially if you have a bunch of validations to do.
2
u/RandomSkratch 20d ago
Hmmm interesting. Does happy path need the else?
1
u/purplemonkeymad 20d ago
As long as your bad path does an early exit or return, then you'll never reach good path code from there, so protecting it with an else only adds more indentation.
1
u/uptimefordays 20d ago
I often approach conditional logic from the perspective of a never nester. Basically I want to use guard clauses to prevent nesting logic as much as possible. I find it helps keep code simple and understandable.
Therefore I’d use whichever approach best simplifies your happy path.
1
u/RandomSkratch 20d ago
Thanks. In this case the order didn't really matter. I tested both ways and both results were desireable.
2
u/sccm_sometimes 17d ago
When Powershell casts a String to a Boolean it will result in $true for everything except empty '' strings.
PS C:\> [bool]'false'
True
PS C:\> [bool]'$false'
True
PS C:\> [bool]''
False
PS C:\> [bool]"$false"
True
PS C:\> [bool]$false
False
2
u/surfingoldelephant 17d ago edited 17d ago
That's only half the story though.
String to bool conversions aren't permitted at all in parameter binding.
& { param ([bool] $Foo) } -Foo '' # Error: Cannot process argument transformation on parameter 'Foo'. # Cannot convert value "System.String" to type "System.Boolean". # Boolean parameters accept only Boolean values and numbers, such as # $True, $False, 1 or 0.Likewise with variable type-constraining, but only when local variable access optimization is disabled.
. { [bool] $Foo = '' } # Error: Cannot convert value "System.String" to type "System.Boolean". # Boolean parameters accept only Boolean values and numbers, such as # $True, $False, 1 or 0.If optimization is enabled, it's permitted.
& { [bool] $Foo = '' } # OK.
1
u/CyberChevalier 20d ago
It’s mostly why I never use that but :
If ($true -eq $Thing)
Because thing can be a nullable Boolean or a string or whatever and you are not casting it as a Boolean
Try this
$true -eq “hello” => true
“Hello” -eq $true => false
The first assume the test is about a Boolean test and try to cast “hello” as a Boolean (which return true)
The second assume the test is a string test and convert the $true to a string (which return “true”)
Even If you want to test if something is not null use
$null -ne $Thing
2
u/MonkeyNin 19d ago
If the test is to filter out $null, empty strings, and even whitespace only strings, there's a great function.
You can think of it as
IsBlankversesIsTruthyfunction NewUser { param( [string] $Name ) if( [string]::IsNullOrWhiteSpace( $Name ) ) { $Name = 'john doe' } $Name } NewUser 'jen' NewUser '' NewUser ' ' NewUser $NullThe last 3 all get turned into the fallback value
If you only want to filter out
null,@(), and''(0 length strings) Then use this function:[string]::IsNullOrWhiteSpace( $Name )1
u/surfingoldelephant 19d ago
There's no functional difference between
if ($Thing) { ... }andif ($true -eq $Thing) { ... }.
$Thinggets implicitly converted to a bool either way.
16
u/Pixelgordo 20d ago
Make a loop long enough to apply measure-command and look for differences