18

Discussion with a colleague, should $null be on the left or right side of the check? Any examples of why this is important?

$abc = $null
$null -eq $abc
True
$abc -eq $null
True

All ok

$abc = 6,7,$null,8,9
$null -eq $abc
False
$abc -eq $null
*No output*

Can someone explain what is happening when an array is compared?

js2010
  • 23,033
  • 6
  • 64
  • 66
user9924807
  • 707
  • 5
  • 22
  • 2
    Equality in PowerShell is not a symmetrical operation. Per the [docs](https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_comparison_operators): "When the input is a collection of values, the comparison operators return any matching values. If there are no matches in a collection, comparison operators do not return anything." So `$null -eq $abc` tests if `$abc` is `$null` itself, `$abc -eq $null` finds the `$null` values in `$abc` -- and prints nothing, since that's what `$null` looks like when output. (Compare `$abc -eq 7`.) – Jeroen Mostert Oct 03 '19 at 11:16
  • 3
    A potentially less confusing test for `$null`-ness (assuming you don't just want to rely on "falsity" and use `!$abc`) is `$abc -isnot [object]` (and the converse `$abc is [object]` to confirm `$abc` is not `$null`). This avoids any collection unrolling as well. – Jeroen Mostert Oct 03 '19 at 11:23
  • For the reason given by @JeroenMostert, this is one of the PSScriptAnalyzer Rules: [PossibleIncorrectComparisonWithNull](https://github.com/PowerShell/PSScriptAnalyzer/blob/development/RuleDocumentation/PossibleIncorrectComparisonWithNull.md) – boxdog Oct 03 '19 at 11:55

2 Answers2

18

When performing comparison operations, PowerShell will evaluate the first operand the operation to determine if it is a collection or a scalar value. If it is a scalar, it will compare the operands to each other as whole objects.

2 -eq 1,2,$null,3
False

$null -eq 1,2,$null,3
False

4 -eq 1,2,$null,3
False

If it is a collection, it will iterate through the collection comparing each element to the second operand and return the value of the second operand if it finds a match.

1,2,$null,3 -eq 2
2

1,2,$null,3 -eq $null
<nothing appears, indicating returned value is $null>

1,2,3 -eq 4
<nothing appears, indicating returned value is $null>

The key difference between the second and third examples. Unless you know absolutely whether the second operand is always or never $null, you can't trust the output of the comparison operation.

On a side note, if both operands are collections, -eq returns $null in every case, because you can't use -eq to compare collections.

So to answer the question, it is generally good practice to put $null on the left side because when using $null in a comparison operation, it is assumed that you want to compare scalar values. If that assumption is wrong, then $null may be better placed on the opposite side, but it's not likely.

Contrarily, I always put $null on the right side because I write my code under the aforementioned assumption - that I am always comparing scalar values when $null is explicitly mentioned in the comparison operation. That way, when I get a non-boolean value returned, I know that I have not accessed my collection object properly in the equation. I have gotten caught in the trap, however, so my coding practices may be better served by changing my ways.

In conclusion, like any coding practice, it's a matter of opinion. Were I to teach PowerShell, I would teach this practice. However, I find it unlikely I will change my seditious ways.

  • 3
    And `1,$null,$null,3 -eq $null` returns `$null,$null`, which is a collection with 2 elements, which is truthy (`if(1,$null,$null,3 -eq $null){ Do-Something }` will execute the if-block). – Mike Rosoft Feb 24 '22 at 12:39
2

-eq is different with arrays on the left. A lot of operators are.

1,2,3 -eq 2

Output:

2

So instead of 2, in your case it's returning $null, because $null is in the array.

js2010
  • 23,033
  • 6
  • 64
  • 66