Reputation: 24430
Question
Why is $null + @{}
valid, but @{} + $null
not; even where null is cast to a hashtable (@{} + ([hashtable]$null)
).
Example Code
[hashtable]$a = @{demo1=1;demo2='two'}
[hashtable]$b = @{demo3=3;demo4='Ivy'}
[hashtable]$c = $null
#combining 2 hashtables creates 1 with both hashes properties (would error if any properties were common to both)
write-verbose 'a + b' -Verbose
($a + $b)
#combining a null hashtable with a non-null hashtable works
write-verbose 'c + a' -Verbose
($c + $a)
#combing 2 null hashtables is fine; even if we've not explicitly cast null as a hashtable
write-verbose 'c + null' -Verbose
($c + $null)
#however, combinging a hashtable with null (i.e. same as second test, only putting null as the right argument instead of the left, produces an error
write-verbose 'a + c' -Verbose
($a + $c)
Output
Name Value
---- -----
demo3 3
demo4 Ivy
demo1 1
demo2 two
VERBOSE: c + a
demo1 1
demo2 two
VERBOSE: c + d
VERBOSE: a + c
A hash table can only be added to another hash table.
At line:19 char:1
+ ($a + $c)
+ ~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : AddHashTableToNonHashTable
Side Note
Incidentally, this led me to discover this useful trick for a null-coalescing operation for hashtables: ($c + @{})
. e.g. ($a + ($c + @{}))
avoids the error produced above / (($a + @{}) + ($c + @{}))
gives us a completely safe way to add hashtables where either value may be null.
Upvotes: 2
Views: 250
Reputation: 29013
I tried to find out exactly why, but I can't for sure.
My original beliefs were:
"1"+1
the 1 on the right becomes a string and the output is "11"
, but 1+"1"
the right becomes a number and the output is 2
.
$null + @{}
would either throw a cast error, or cast and do null + null = null, not output an empty hashtable as it does.A.op_Addition(B)
and it will be up to the thing on the left to say what happens when you try to add the thing on the right to it.
@{} + 0
tells you that a hashtable can only be added to a hashtable. (Lies, you can add it to null). And 0 + @{}
tells you that hashtables do not contain an op_Addition
method. So the addition with null seems like it should give that error, but doesn't, because it's not falling back to this mechanism.The PSv3 language spec (which I think is the latest version available), download here: https://www.microsoft.com/en-us/download/details.aspx?id=36389, mentions addition:
7.7.1 Addition Description: The result of the addition operator + is the sum of the values designated by the two operands after the usual arithmetic conversions (§6.15) have been applied.
The usual arithmetic conversions say:
If neither operand designates a value having numeric type, then [..] all operands designating the value $null are converted to zero of type int and the process continues with the numeric conversions listed below.
That implies $null gets converted to 0 in both your examples. Although that cannot be happening because 0 + @{}
and @{} + 0
are both errors.
There is an explicit mention of adding of two hashtables in section 7.7:
7.7.4 Hashtable concatenation Description: When both operands designate Hashtables the binary + operator creates a new Hashtable that contains the elements designated by the left operand followed immediately by the elements designated by the right operand.
OK, hashtable addition is handled by the PowerShell engine, but only adding two hashtables.
Section 7. introduction says:
Windows PowerShell: If an operation is not defined by PowerShell, the type of the value designated by the left operand is inspected to see if it has a corresponding op_ method.
And the operation $null + Hashtable doesn't seem to be defined by PowerShell from what I can see in the spec, and the corresponding method for +
is op_Addition
- a method which hashtables do not have, see error code earlier - and this is not throwing that error, and not only that but in the case of adding to 0 the error comes from the Right operand not the left one.
And the other interesting bit in the spec is:
4.1.2 The characteristics of the null type are unspecified.
So the summary appears to be:
@{} + $null
- is triggering the PowerShell handling of adding two hashtables, even though the spec doesn't say that it will.$null + @{}
- it looks like there's an implicit $null + x = x
rule, although the spec doesn't seem to mention it, and it might be implementation dependent.[<type>]$null
- casting $null to a numeric type results in 0 (6.15 arithmetic conversions), but casting it to anything else(?) appears to result in $null (not in the spec).$null
has no type are against the PowerShell spec 4.1.2 "the null type" which says "The null type has one instance, the automatic variable $null (§2.3.2.2), also known as the null value. The characteristics of this type are unspecified." so at least in terminology, it's described as a type in PowerShell even if you can't GetType() on it .. Upvotes: 2