Surprising behavior of @() (array subexpression operator) with arrays/collections created with New-Object
See original GitHub issuetl; dr:
This issue is written based on the following, currently unfulfilled expectation:
- When you wrap a
New-Objectcall that outputs an array / collection in@(), it should not create an array wrapper around it.
@PetSerAl disagrees with my expectation (quotes from the comments on this SO post that inspired this issue, part of which is reprinted below):
What is unexpected about this behavior?
New-Objectwrites a single element to the pipeline and@()wraps it in an array.
On the tangentially related issue that @() preserves the specific array type:
Also, IMHO,
@([int[]] (1, 2)).GetType().Name[returningInt32[]] is a bug (over-optimization; it returnsObject[]in v2)
As of Windows PowerShell v5.1 / PowerShell Core v6.0.0-beta.4, @() unexpectedly wraps arrays / collections instantiated directly as .NET types with the New-Object cmdlet in an outer, single-element array; in other words: it doesn’t recognize that the results already are array-valued:
> @(New-Object 'Object[]' 2).Count; @(New-Object 'Object[]' 2)[0].Count
1 # !! The array was unexpectedly wrapped in an outer single-item array.
2 # !! Element [0] contains the original array.
> @(New-Object 'System.Collections.ArrayList').Count; @(New-Object 'System.Collections.ArrayList')[0].Count
1 # !! The array list was unexpectedly wrapped in an outer single-item array.
0 # !! Element [0] contains the original (empty) array list.
To contrast the surprising New-Object behavior above with commands that should be equivalent, but work as expected:
> @((New-Object 'Object[]' 2)).Count
2 # OK - !! Simply enclosing the New-Object call in (...) made the difference.
> @([int[]] (1, 2)).Count
2 # OK - using a cast in lieu of New-Object
> @([System.Collections.ArrayList]::new()).Count
0 # OK - using the static ::new() method in lieu of New-Object
Environment data
PowerShell Core v6.0.0-beta.4 on macOS 10.12.5
PowerShell Core v6.0.0-beta.4 on Ubuntu 16.04.2 LTS
PowerShell Core v6.0.0-beta.4 on Microsoft Windows 10 Pro (64-bit; v10.0.15063)
Windows PowerShell v5.1.15063.413 on Microsoft Windows 10 Pro (64-bit; v10.0.15063)
Issue Analytics
- State:
- Created 6 years ago
- Comments:16 (16 by maintainers)

Top Related StackOverflow Question
@daxian-dbw But where I can see that definition of array expression? Before now I always expect it to return new array object each time. I myself use
$b = @($a)(without cast although) as array copy operator, and I really do not like if it stop copying array at some point in the future.Great discussions!!!
@PetSerAl is right, PowerShell unravels collection results from expressions, but not commands. Commands themselves decide whether the result writen to pipe should be unravelled or not (
Cmdlet.WriteObject(object)andCmdlet.WriteObject(object, enumerateCollection)for C# andWrite-OutputandWrite-Output -NoEnumeratefor script).As for the quote, here is more context on it:
I think the point is that you don’t need a notation (beginning char sequence + closing char sequence) to create an array in PowerShell, for example,
1,2,3,4is defining an array. But PowerShell does haveArrayLiteralRulein parser andArrayLiteralAst.The
ArrayLiteralAstis embedded in theConvertExpressionAst: