8

Looking that the help section about_Comparison_Operators of PowerShell I understand this:

PS C:\> $false,$false -eq $true
PS C:\> 

Nothing from the left matches the right so nothing is returned not even a $null.

I don't understand this:

PS C:\> $true -eq $false,$false
True
PS C:\> 

Is it because it's first doing $true -eq $false which returns False, and then taking that False and doing $false -eq $false which returns True?

More Info

The reason the below returns false is because it's comparing a string to an array, correct? A string is not equal to an array.

PS C:\> "abc" -eq "abc","def"
False

Answer?

More digging shows that $true is equal to an object.

PS C:\> $true -eq [array]
True
PS C:\> $true -eq [string]
True
PS C:\> $true -eq [int]
True
PS C:\> $true -eq [bool]
True

It's the values of those object that matter.

PS C:\> $true -eq [int]0
False
3
  • +1 Good question, but can I ask what you need it for? I'm having troubles seeing a scenario where I could use it. Commented Apr 9, 2013 at 21:31
  • To learn how PowerShell works. Also looking at the link not sure why "abc" -eq "abc", "def" doesn't work. Commented Apr 9, 2013 at 21:36
  • You need to earn your strips Commented Apr 9, 2013 at 21:40

3 Answers 3

7

I like fundamental questions about the behavior and features of the language like this... Give's me an excuse to read the PowerShell language specification.

You can download said specification: 2.0 and 3.0. See section 7.8.1 - Equality and relational operators.

For the first part of the question, something actually is returned - an empty array, which is illustrated by: ($false,$false -eq $true).psbase

Length         : 0
LongLength     : 0
Rank           : 1
SyncRoot       : {}
IsReadOnly     : False
IsFixedSize    : True
IsSynchronized : False
Count          : 0

From the spec -

If the value designated by the left operand is not a collection, the result has type bool. Otherwise, the result is a possibly empty unconstrained 1-dimensional array containing the elements of the collection that test True when compared to the value designated by the right operand.

For the second part, because the left operand is itself a bool, I think that it always be the result. This is only when the right operand is a collection.

Some examples:

$true -eq 1,2,3,4
$true -eq '','','',''
$true -eq '',1,$true,$false
$true -eq $null,$false,1,''

All of these return $true. Conversly all of these return $false

$false -eq 1,2,3,4
$false -eq '','','',''
$false -eq '',1,$true,$false
$false -eq $null,$false,1,''
$false -eq $true,$true,$true

The type of the left operand is very important. This wil return $true: $false -eq 0 because the right operand is castable to the type of the left operand.

Sign up to request clarification or add additional context in comments.

11 Comments

Andy's on the mark. The logical expression is processed left to right, and the type of the left operand determines how the right operand is interpreted. If you're having trouble visualizing the spec, break the logic down and examine the casts PowerShell is performing: [bool]0; [bool]1; [bool]@(); [bool]@($false); [bool]@($false,$false); [bool]''; [bool]$null; #ad nauseum...
I'd expect these to evaluate the same, but they don't: [bool](@(1) -eq 1) [bool](1 -eq @(1))
First: -eq returns 1 from the collection, then cast to bool makes it $true. Second -eq returns boolean because the left operand is a scaler, and cast as a bool leaves it false. I'm not sure what PowerShell does to determine the boolean when the right operand is a collection. The spec doesn't say anything about it specifically, so its a fun game for us to deduce :D
If you replace the [int] 1's with [string] 1's they evaluate the same.
@AndyArismendi,@mjolinor: To rephrase beefarino's comment, standard equality coerces the right operand to the type of the left operand and then compares left and right. The only special case is when left is a collection (then equality is tested on each element of left, and the matching elements returned). So for '1' -eq @(1) and '1' -eq @('1'), right is coerced to the string '1' before comparison ('1 0' -eq @('1','0') will also return true, for the default value of $OFS); for 1 -eq @(1), right cannot be coerced to an integer and comparison returns false.
|
3

Best guess:

It's evaluating as True because it's an array with more than one member. An array does not have a ToBoolean() method.

As long as it's a scalar, or an array with only has one member Powershell can coerce that to a scalar and get to a ToBoolean() method on the member. As soon as it goes to 2 or more, it always returns True, regardless of what the elemets are. If there's no ToBoolean(), and it falls back to the default ToString() method, that's always going to evaluate to True.

Or maybe not.

1 Comment

I added a ToBoolean method returning false to an arraylist but the comparison returned false testing $false -eq $array_list_with_to_bool. So i'm not sure if it's because of the existance of a method named ToBoolean.
2

Perhaps the -eq operator is evaluating their existence (aka not $null) rather than their value.

Similar to the IF statement perhaps?

PS> if("anyval"){$true}else{$false}
True

This answer provided by @Joey might also prove useful.

1 Comment

Actually, I think the link you provide IS the answer.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.