I would expect $c to contain an empty list
You shouldn't expect that, it's not a Python-style list comprehension which always builds a list - even if the list is empty.
It's a putting objects through the pipeline, through a filter test, and storing the pipeline output. If nothing gets through the filter, there's no output to store. The pipeline doesn't conjure up an empty array from nowhere - that would be misleading and annoying. This is where the answer about the array constructor comes from - wrapping with @( ... )
is building an array with the pipeline output as the contents, and no output means an empty array.
And you're taking risks by using .Length
instead of .Count
. e.g. if you did that with strings, then an intersection of nothing would return no length, an intersection of two items would return 2, but an intersection of one item would return the length of the string:
$a = 'abc','cde','def'
$b = 'ghi','jkl','def'
$c = $a |?{$b -contains $_} #c = 'def'
$c.length # 1 item, length 3
It's not a problem if you're working with numbers that have no length property, but I think it's a better idea to habitually use .Count
for getting the number of items in a collection.
Also see this answer: https://stackoverflow.com/a/26513523/478656 for related discussion on Length vs. Count properties, and how they were changed in PSv3+ to make working with empty things easier.
Which brings me to your claim:
I get a $null
(which issues an exception when queried for .length
)
It ... doesn't?
($null).Length # $null in PSv2, 0 in PSv4, PSv5.1. No exception.
Unless you're running in 'strict' mode?