Many thanks to everyone who contributed answers to this little puzzler! I was actually a bit surprised at the volume - hopefully you found it fun and educational.
First, let’s get a definitive answer down for this one…
Query
In PowerShell, when is the following statement true? Explain why.
( $a -eq $b ) -ne ( $b -eq $a )
Answer
At first glance this may not seem possible. The trick is in understanding how PowerShell evaluates the equality operation when the types of $a and $b vary.
There are two general cases to consider here: when $a is scalar, and when $a is an array.
Scalar Equality and Type Conversion
If you’re not familiar with the term scalar, I’m using it to mean a variable containing “a single value” as opposed to an enumerable collection type, such as an array or list. Yeah, it’s from Perl, so what? (Note that the string type, while technically an enumerable collection of characters, is considered a scalar value here.)
Type the following in your PowerShell console (seriously (I SAID DO IT)):
$a = 0;
$b = '';
$a -eq $b
What do you get? True! Which makes sense, since 0 and an empty string both sort of mean “nothing” or “no result,” right? Now type this:
$b –eq $a
Boom goes the dynamite: False. So what’s happening here? It may help to replace the variables with their actual values:
0 –eq '' # true case
'' -eq 0 # false case
When PowerShell evaluates this comparison, it begins by taking the left operand at face value. Since the right operand is of a different type, PowerShell is forced to coerce its type to match the type of the left operand. The reason for the false case becomes fairly obvious when you spell out the conversion PowerShell is doing on your behalf:
0 –eq [int]'' # true case
'' –eq [string]0 # false case
In the true case, the conversion of an empty string into an integer value of 0 makes sense, and the equality expression is true. In the false case, the conversion of the number 0 into a string results in a string containing a single character ‘0’, which is different than the empty string and the expression is false. You can verify these conversions in your console:
[int]'' # 0
[string]0 # 0
This hidden coercion can lead to some fairly interesting results, to put it mildly. Try this one, it’ll blow your mind:
$a = $null;
$b = [string]$null;
$a -eq $b
Yep, that’s right: ($null) doesn’t equal ($null cast to a string) in PowerShell. Have you ever passed $null to a .NET method that accepts a string? No, you haven’t: you’ve passed an empty string without knowing it…
Arrays and –eq
Several puzzlers pointed out that –eq behaves differently when the left operand is an array; while not the answer I was looking for it’s just as correct as the previous one.
The easiest way to describe this is by example; try this in your PowerShell host of choice:
$a = 1,2,3,4,5;
$b = 3;
$a -eq $b
$b -eq $a
When the left operand is an array, –eq returns the members of the array that equal the right operand. In this case, $a –eq $b returns the integer 3. Reversing the order of operands naturally changes the expression, and since there is no way to convert an array of numbers to a single integer the comparison is false.
This is an awesome example of PowerShell’s penchant for lists and enumeration, and it applies to many of the binary operators it supports:
'aabb','bbcc','zzaa' -replace 'a','q'
The Takeaway
The lesson here is that while PowerShell isn’t a strongly-typed language like C#, it does have solid roots in the .NET type system and leverages it in many interesting and “helpful” ways. If you’re not careful, you’ll get burned.
Winner
Ah, I almost forgot!
Choosing the winner on the merit of the answers turned out to be tough – everyone did a really great job. Some explanations were better than others, but it was difficult to isolate one as the best. Thankfully I have PowerShell's get-random to turn this into a “business decision.”
And the author of the winning answer and receiver of a license for the immensely cool SeeShell software module published by the devastatingly handsome folks at Code Owls is….
JOSH CARROL
Thanks for playing everyone - since this was so much fun let’s say we do it again soon. For now though, focus on those upcoming Community Scripting Games!