(ConvertFrom-Json "[]") -eq @()
#return False should return True
(ConvertFrom-Json "[]") -eq $null
# => returns True, should return False
_Comment_
ConvertFrom-Json on Windows PSVersion = 5.1.18362.752 returns the correct value
$PSVersionTable
Name Value
---- -----
PSVersion 7.1.0-preview.6
PSEdition Core
GitCommitId 7.1.0-preview.6
OS Darwin 19.6.0 Darwin Kernel Version 19.6.0: Thu Jun 18 20:49:00 PDT 2020; root:xnu-6153.14…
Platform Unix
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0
/cc @iSazonov
This is probably down to Newtonsoft.Json's handling of this input, I'd imagine... 🤔
The ConvertFrom-Json default behavior was changed in v7 to exhibit the typical PowerShell behavior of _enumerating_ arrays in the pipeline; thus, an empty array sends _nothing_ through the pipeline (see #3424).
If you want to preserve a parsed-from-JSON array, use the -NoEnumerate switch:
# Output is, loosely speaking, $null
# (technically, [System.Management.Automation.Internal.AutomationNull]::Value)
PS> (ConvertFrom-Json "[]") -is [array]
False
# -NoEnumerate sends the (empty) array as-is, as whole to the pipeline.
PS> (ConvertFrom-Json "[]" -NoEnumerate) -is [array]
True
@mklement0 -- I see your point. If I use -NoEnumerate that also resolves the unexpected unboxing of e.g. ["singleton"].
Hmm. okay. So this is by design because returning $null rather than empty @() is the idiomatic thing for empty lists in powershell?
Technically it's [System.Management.Automation.Internal.AutomationNull]::Value but yeah PowerShell will (almost) always treat that the same as $null (@mklement0 has a list of issues somewhere about the cases it does not 😂); it's the "nothing" value in a sense.
@chrisfcarroll, to add to @vexx32's comment:
also resolves the unexpected unboxing of e.g. ["singleton"].
Indeed (I assume you mean unwrapping rather than unboxing).
It is the same behavior you get with Write-Output -NoEnumerate, for instance: instead of the default pipeline behavior of _enumerating_ collections - sending their elements one by one - -NoEnumerate requests sending the collection _as a whole, as a single object_.
Sending an _empty_ collection to the pipeline therefore sends _nothing_, which you can verify with
@() | ForEach-Object { "hi" } (no output).
_Saving_ non-output from a command is technically represented as [System.Management.Automation.Internal.AutomationNull]::Value, as @vexx32 states. While this value _typically_ behaves like $null, it behaves differently _in the pipeline_ (cf. $null | ForEach-Object { 'hi' }, which _does_ produce output) and in other _enumeration_ contexts; #13465 is trying to make this difference more discoverable.
Also: -eq @() doesn't work as you might expect, because with an array LHS -eq acts as a filter that returns _matching LHS elements_ rather than a Boolean, whereas an array-valued RHS is always _stringified_:
PS> @() -eq @() # RHS is effectively treated as '' (empty string).
# !! No visible output; but the output is actually again @() (empty array)
That is, no elements in the empty-array LHS was equal to '', so the result is an empty array (the sub-array of matching LHS elements).
To test an array for being empty, the simplest test is .Count -eq 0, but note that you may have to separately test if the operands is indeed an array (if that distinction is important), because $null.Count and 'foo'.Count work too (caveat: only if Set-StrictMode is off or at most -Version 1 - see #2798), and return 0 and 1, respectively.
Having read #3424 I can see that keeping this open as a bug would be 2½ years you don't want to rewind …