Scroll Top
Evotec Services sp. z o.o., ul. Drozdów 6, Mikołów, 43-190, Poland

The curious case of $null should be on the left side of equality comparisons PSScriptAnalyzer

img_5cc0645e15f23

If you're using VSCode with Powershell extension, you probably got used to PSScriptAnalyzer giving you all kind of tips on optimizing things. It makes your code better. Chris Bergmeister does a great job working on it. One of the tips PSScriptAnalyzer gives you when you use $null on the right side of the comparison.

$Process = Get-Process
if ($Process -eq $null) {
    #DoSomething
}

For a long time, this was my standard code until I started using VSCode and got the tip from PSScriptAnalyzer to use it differently. Like that:

$Process = Get-Process
if ($null -eq $Process) {
    #DoSomething
}

From the english perspective, this should be the same, but well it really isn't.

Explanation for $null comparison

When I asked Chris about it, he explained the reason with following code

if (@() -eq $null) { 'true' }else { 'false' }
if (@() -ne $null) { 'true' }else { 'false' }

Fair enough right? Full rule documentation is available here. As documentation describe it there are reasons why this should occur:

$null is a scalar. When the input (left side) to an operator is a scalar value, comparison operators return a Boolean value. When the input is a collection of values, the comparison operators return any matching values, or an empty array if there are no matches in the collection. The only way to reliably check if a value is $null is to place $null on the left side of the operator so that a scalar comparison is performed.
PowerShell will perform type casting left to right, resulting in incorrect comparisons when $null is cast to other scalar types.

Accepting this truth made me start using $null religiously on the left side of the comparison.

When it is not a good idea to have $null on the left side

I could end the article here, saying “and they lived ever after” if I wouldn't hit a problem today because of that rule. You see I started to trust that rule without even thinking about it. The moment VSCode would tell me to fix it, I would go and fix it. So any time I would see this rule popup I would fix it and go my way:

The problem is I wasn't really testing after I changed this, every time I did it. I even started to do it for some old code and simply fixed it for peace of mind. Until I noticed that one of my scripts using RunSpaces stopped working today. Let's take a look at the code that is simplified version of it:

$Object1 = @{
    Name   = 'Test1'
    Status = 1
}
$Object2 = @{
    Name   = 'Tests2'
    Status = $null
}

$Array = @($Object1, $Object2)

$Test1 = While ($Array.Status -ne $null) {
    $true
    foreach ($A in $Array) {
        $A.Status = $null
    }
}

This code merely is supposed to set $null value in Status property of two objects: $Object1 and $Object2. While of course you usually wouldn't use While for such case, but in my code I did. When you run the code above you will get $true as an output of $Test1 variable. Everything according to plan, but with one problem – $Array.Status comparison complaining that I'm using $null on the wrong side. Let's fix it. For comparison purposes, I left both loops in the code.

$Object1 = @{
    Name   = 'Test1'
    Status = 1
}
$Object2 = @{
    Name   = 'Tests2'
    Status = $null
}

$Array = @($Object1, $Object2)

$Test1 = While ($Array.Status -ne $null) {
    $true
    foreach ($A in $Array) {
        $A.Status = $null
    }
}

$Test1

$Test2 = While ($null -ne $Array.Status) {
    $true
    foreach ($A in $Array) {
        $A.Status = $null
    }
}

$Test2

Let me know when it's done? Well, actually, it will never finish. It seems that changing order around makes it an infinite loop. Totally not what I expected. I trusted PSScriptAnalyzer a bit too much on this front.

Moral

Moral of this story? Test your code after making changes, even those that seem like a minor change. I'll, of course, ask Chris to clarify this for me, and maybe he can add some workaround for PSScriptAnalyzer to not show this suggestion if it's used on Array. Make sure to follow him on Twitter. He makes it better for us, users of VSCode and PowerShell Extension.

Posty powiązane