Repository navigation
Member-access enumeration should not apply pipeline enumeration logic #6802
Description
Note:
-
The behavior described below is by design and has been in place since member enumeration was introduced in v3.
- While it's most likely too late to change this behavior, I'm offering my observations in the context of the "PowerShell vZeroTechnicalDebt" discussion - see Is it time for "PowerShell vZeroTechnicalDebt" ("vNext") and/or for an opt-in mechanism into new/fixed features that break backward compatibility? #6745.
-
A request to officially document the current behavior can be found here, which arose out of the since-closed Member enumeration unwraps and flattens array-valued properties #6454.
- This is a follow-up to the latter to further clarify why the existing behavior is problematic.
Currently, <objOrCollection>.<member> is equivalent to
<objOrCollection> | ForEachObject { $_.<member> }.
That is, pipeline logic is applied when collecting the member values from a collection's elements:
# A member collected from a single-element collection is unwrapped.
# The following returns *scalar* 1:
PS> (, @{ a = 1 }).a.GetType().Name
Int32 # suggested alternative: (, 1) (single-element array)
# Collecting array-valued members *concatenates* the arrays.
# The following returns *flat* array 1, 2, 3, 4:
PS> (@{ a = 1, 2 }, @{ a = 3, 4 }).a.Count
4 # suggested alternative: (1, 2), (3, 4); a 2-element array containing the member arrays as-isThe current behavior is problematic for the following reasons:
-
It is generally surprising that pipeline logic is invisibly applied, given that member enumeration applies to expression mode only.
-
Intuitively, one would expect member values to be collected as-is, not to be concatenated if they happen to be array-valued.
-
The unwrapping of a single member value is especially counterintuitive in combination with
@(...):
$objOrColl = @{ Name = 'foo' }
# Ensure that $objOrColl is *array*-valued with @(...) so that -like acts as an array *filter*.
# Currently the use of .Name negates the effect of @(...):
@($objOrColl).Name -like 'f*'
True # !! LHS evaluated to a *scalar* and returns a Boolean rather than the intended 'foo'Enclosing the entire expression in @(...) solves the problem, but that's not obvious and shouldn't be necessary: @($objOrColl.Name) -like 'f*'
Additionally, in the no-input-object case, member enumeration returns $null rather than [System.Management.Automation.Internal.AutomationNull]::Value, which can also lead to surprising behavior:
$pids = @((Get-Process *NoSuchProcess*).Id)The intuitive expectation is for $pids to contain an empty array, but, because $null was output by the member enumeration, the actual result is @($null), i.e. a single-element array containing $null.
Environment data
Written as of:
PowerShell Core v6.0.2
Activity
[-]Member enumeration should not apply pipeline enumeration logic[/-][+]Member-access enumeration should not apply pipeline enumeration logic[/+]microsoft-github-policy-service commentedon Nov 16, 2023
This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.
microsoft-github-policy-service commentedon Nov 16, 2023
This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.
microsoft-github-policy-service commentedon Nov 23, 2023
This issue has been marked as "No Activity" as there has been no activity for 6 months. It has been closed for housekeeping purposes.