Skip to content

a $This: modifier #26645

@iRon7

Description

@iRon7

Summary of the new feature / enhancement

This request is an extent on the enhancement request #13772 and might be a better alternative as it is universal (not limited to a single variable name), consistent and probably less expensive.

PowerShell has a nice feature which regards to scope rules:

  • When code running in a runspace references an item, PowerShell searches the scope hierarchy, starting with the current scope and proceeding through each parent scope.
    • If the item isn't found, a new item is created in the current scope.
    • If it finds a match, the value of the item is retrieved from the scope where is was found.
    • If you change the value, the item is copied to the current scope so that the change only affects the current scope.

As with several other PowerShell features, it has its advantage, but it also has its disadvantages (and pitfalls) as this actually means that you do not have to define your variable but should make absolutely sure you variable is initiated 🤔(otherwise it might take it from a parent scope).

In other words, a common use case is keeping track of an (zero or one based) index in a foreach loop:

function MyFunction {
    $Table = @{}
    'Zero', 'One', 'Two', 'Three' | ForEach-Object { $Table[$Index++] = $_ }
    $Table | Format-Table
}

MyFunction

This works fine until you use the variable $i in one of the parent functions (where the action "If the item isn't found, a new item is created in the current scope" will take place):

for ($Index = 0; $Index -lt 5; $Index++) { <# do something #> }
MyFunction

To resolve this I need to make sure that the concerned variable ($Index) is (re)set:

function MyFunction {
    $Table = @{}
    $Index = 0
    'Zero', 'One', 'Two', 'Three' | ForEach-Object { $Table[$Index++] = $_ }
    $Table | Format-Table
}

But that the $Index sequence is ment to be zero based ($Index = 0) is quiet obvious and would be clearer when described in the ScriptBlock ({ $Table[$Index++] = $_ }) itself.

Proposed technical implementation details (optional)

Wishful thinking:

A scope modifier (I was thinking of $this:) that acts like the default rules with one exception that doesn't search the scope hierarchy, starting with the current scope and proceeding through each parent scope but initializes the variable with its default value (basically: New-Variable -Name <Name>) whenever the current item ($_) is initialized:

A zero based iteration:

'Zero', 'One', 'Two', 'Three' | ForEach-Object { $Table[$this:Index++] = $_ }

A one based iteration:

'One', 'Two', 'Three' | ForEach-Object { $Table[++$this:Index] = $_ }

#13769 Skip certain indices

'A'..'E' | Where-Object { $this:Index++ -notin 1, 3 }

Select odd rows

'A'..'E' | Where-Object { $this.Index++ % 2 }

Combine single arrays into columns

$A1= 1..3
$A2= 4..6
$A3= 7..9

$A1 | Foreach-Object {
    [pscustomobject]@{ A1 = $_; A2= $A2[$this:i++]; A3 = $A3[$this:j++] }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Issue-Enhancementthe issue is more of a feature request than a bugWG-Enginecore PowerShell engine, interpreter, and runtime

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions