Skip to content

Allow early termination of process block #27389

@x5i4k4

Description

@x5i4k4

Summary of the new feature / enhancement

Given following function to get frist item matching the given pattern:

function first {
    param (
        [Parameter(ValueFromPipeline)]
        [psobject]$InputObject,

        [Parameter(Position = 1, Mandatory)]
        [scriptblock]$Selector
    )
    process {
        if ($Selector.InvokeWithContext($null, [psvariable]::new('_', $_))) {
            $_
            # I need termination here when it found first match
        }
    }
}

1..10 | first { $_ % 2 -eq 0 } # expected: 2

I would expect it terminate the process when it found a match, we have following possible workarounds:

  • return: aka continute for process but it will keep spinning for rest of the reduandant items
  • break: not sure about its semantic, it can early break the process but has the following problem:
function first {
    param (
        [Parameter(ValueFromPipeline)]
        [psobject]$InputObject,

        [Parameter(Position = 1)]
        [psobject]$Selector = 1
    )
    process {
        if ($Selector.InvokeWithContext($null, [psvariable]::new('_', $_))) {
            $_
            break
        }
    }
}

1..10 | first { $_ % 2 -eq 0 } | select -f 1 # 2
1..10 | first { $_ % 2 -eq 0 } | measure # none

For certain cmdlet like measure, it can't receive the items from first using break? While select works fine. Should it be considered as bug?
Given another function collect that collect everything from pipeline and return in end block, also reproduces the problem.
So looks like break not only breaks the process, it also skip the end block evaluation?

function collect {
    begin {
        $foo = [System.Collections.Generic.List[object]]@()
    }
    process {
        $foo.Add($_)
    }
    end {
        $foo
    }
}

1..10 | first { $_ % 2 -eq 0 } | collect # none

Proposed technical implementation details (optional)

Adding new keyword can be unnecessary, simply add a new method $PSCmlet.Break() or something should be sufficient.
Or just make break to eval end block as well(potentially breaking change), if I understand the problem correctly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Issue-Enhancementthe issue is more of a feature request than a bugNeeds-TriageThe issue is new and needs to be triaged by a work group.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions