Historically yield return has not been required in PowerShell since all output is written to the pipeline as it's returned. However, with the introduction of classes, we now rely on a single return path for each class. Where such a method is expected to output an array of items, in some cases it may make more sense to drip-feed results to the pipeline, rather than return the collection as a whole once gathered. Currently there is no way to do this.
See also: Related StackOverflow post.
I kind of agree with this being nice to have, but, anytime I have been presented with a use-case it ended up being something that was better handled by a function/cmdlet. I'm not saying there is no good use-case, just that every time I personally have been presented with this, the use-case was weak.
Do you have some use-cases for this?
@markekraus Sample Use Case:
I have a base (effectively abstract) class, Fetcher. Classes SqlFetcher and RestFetcher extend this class, providing methods for pulling data from SQL or from Rest services. This then allows me to write functions to gather data which don't care about the technology. i.e. These functions take an instance of a Fetcher class, initialised to point at the relevant database or web service.
When I call the class's method GetData() it gathers and returns this data to the pipeline. However, there are filters which can only be applied in PowerShell (e.g. they rely on a regex; a query type not possible in the other languages), so after getting the results I need to filter them. I only need the first match; so if this match is in the first 10 results returned I don't want to incur the expense of returning all 1,000 results of the query I sent to Fetcher.
@JohnLBevan
In that use case, haven't you already incurred the cost of those 1,000? Does matter where you are processing them, whether you did it inside a method or outside in the pipeline?
Unless you are saying that the resource is also yielding. In which case you can have class that inherits from your abstract class and overload GetData() with a Regex object and let the class handle the exit.
Again, I'm not arguing we shouldn't have return yield. Just playing devils advocate.
@markekraus
In that use case, haven't you already incurred the cost of those 1,000?
In the SQL example probably not. SQL's done the work of determining which results to return, but if we're using a SqlDataReader (i.e. as opposed to a SqlDataAdapter), then we only need to fetch those values back from the server row by row. In a scenario where I knew I may not require all results I'd opt for the data reader over the adapter.
For the REST example; fair enough you'd need to get the full result before parsing it... However if I amend the use case to mention that the service we're calling requires paging then it's once again a valid use case; since we avoid the round trip every N (page size) records.
No worries with the suggestion being debated; completely agree that requirements should be justifiable.
You can use LINQ as a sort of work around. Here's how you could do your stack overflow example.
using namespace System.Collections.Generic
using namespace System.Diagnostics
[int]$i = 0
class Demo {
[IEnumerable[Process]] GetPowershellProcesses() {
return [Linq.Enumerable]::Select(
[Process[]](Get-Process *powershell*),
[Func[Process, Process]]{ param($p) $global:i++; $p })
}
}
$demo = New-Object Demo
$demo.GetPowerShellProcesses() | %{ "$i - $($_.ProcessName)" }
However, variables from that scope may or may not be available depending on if the SessionStateScope that the enumerable was created in is still active during enumeration. This would likely also be an issue in any implementation of yield in PowerShell with the way script blocks currently work.
Most helpful comment
You can use LINQ as a sort of work around. Here's how you could do your stack overflow example.
However, variables from that scope may or may not be available depending on if the
SessionStateScopethat the enumerable was created in is still active during enumeration. This would likely also be an issue in any implementation ofyieldin PowerShell with the way script blocks currently work.