-
Notifications
You must be signed in to change notification settings - Fork 8.2k
Expose the .ForEach() and .Where() methods as regular PowerShell operators #6576
Description
Note:
- This proposal arose out of the discussion in Collection operators .Where() and .ForEach() do not unwrap single-item results #6512
- An RFC would have to be written, but I first want to see if there's a fundamental willingness to implement this.
The hidden and effectively undocumented .Where() and .ForEach methods available on every object exposed by PowerShell were introduced to support DSC in v4 and provide functionality similar to the Where-Object and ForEach-Object cmdlets, but (a) in a more performant way (albeit in an all-in-memory way) and (b) with more features. The most comprehensive documentation that I'm aware of is this blog post by @KirkMunro.
While they could simple be documented (and made more discoverable), I suggest surfacing them as bona fide PowerShell operators -foreach and -where:
-
No native PowerShell features that I am aware of are exposed as methods: instead, functionality is surfaced as commands (cmdlets/functions) and operators.
- Methods belong to a different realm, to which
Get-Help about_Methodsis the portal (albeit one that, unfortunately, currently doesn't discuss syntax pitfalls and doesn't even referenceGet-Help about_Parsing); it's a powerful realm and definitely worth knowing about, but it is a different realm, distinct from how PowerShell itself surfaces its functionality.
- Methods belong to a different realm, to which
-
The
.Where()and.ForEach()methods were introduced as such for the benefit of DSC -of necessity, I presume, given that the DSC DSL doesn't allow use of pipelines(see comments below).-
Despite their general availability inside PowerShell itself, they're effectively undocumented, and many people may not even be aware of their existence (since
tab completion doesn't help(see comments below), and neitherGet-Membernor.psobject.Methodsfind them, you simply have to know of their existence). -
Even if fully documented (and, as discussed, this is currently even lacking in the DSC context, and overall Kirk's blog post is still the most complete documentation), these methods make awkward tools in general PowerShell use, due to their method syntax and output data types.
-
Hence my suggestion to surface them as operators with [object[]] output, which would make them discoverable interactively (-<tab>) , and they would be documented alongside the existing operators.
They'd make concise complements to their cmdlet counterparts; -foreach would make the foreach loop unnecessary in many situations and with its use of $_ reduce the existing confusion between the loop and the cmdlet (see MicrosoftDocs/PowerShell-Docs#1514 and a rejected attempt to harmonize the two, #3830):
$var = 1, 2, 3 -foreach { $_ + 1 } # wishful thinking
# vs.
$var = foreach ($i in 1, 2, 3) { $i + 1 }
# or (slower)
$var = 1, 2, 3 | ForEach-Object { $_ + 1 }
# ---
$var = 1, 2, 3 -where { $_ -gt 1 } # wishful thinking
# vs.
# (slower)
$var = 1, 2, 3 | Where-Object { $_ -gt 1 }
# or
$var = foreach ($i in 1, 2, 3) { if ($i -gt 1) { $i } }
Arguably, even DSC could benefit from the cleaner operator syntax; contrast the following:
# Note that this example, taken from https://docs.microsoft.com/en-us/powershell/dsc/separatingenvdata
# doesn't even use `()` around the script-block argument, so the use of Where()
# isn't even readily recognizable as a *method* call.
Node ($AllNodes.Where{$_.Role -eq "WebServer"}).NodeName { ...
# vs.
Node ($AllNodes -where {$_.Role -eq "WebServer"}).NodeName { ... # wishful thinkingEnvironment data
Written as of:
PowerShell Core v6.0.2