PowerShell / PowerShell/PowerShell
Shared immutable storage for function and attributes
Nobody has claimed this yet.
- Dominant language
- C#
- Stars
- 55.5k
- Forks
- 8.5k
- Avg merge
- 1d 2h
- Merged PRs (30d)
- 88
Description
EDIT: use real example, and propose such variables to be evaluated on completion-time(or whatever the name it should have)
Summary of the new feature / enhancement
Motivation
Sometimes I'd like to use same source for both validation attributes and function implementation.
However pwsh doesn't allow to share them as a variable. PowerShell has a great capability to manage completions within same script, I think this feature would make it even better.
The following example replicates $registry variable for real execution and completion, depending on the context of -AllUsers.
# Remove-StartupApplication.ps1
param(
[ArgumentCompleter({
param (
$commandName,
$parameterName,
$wordToComplete,
$commandAst,
$fakeBoundParameters
)
if ($fakeBoundParameters.ContainsKey('AllUsers') -and $fakeBoundParameters.AllUsers) {
$registry = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run'
} else {
$registry = 'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run'
}
Get-Item $registry | ForEach-Object Property
})]
[Parameter(Mandatory)]
[string]$Name,
[switch]$AllUsers
)
begin {
if ($AllUsers) {
$registry = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run'
} else {
$registry = 'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run'
}
$ExePath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($ExePath)
}
end {
Remove-ItemProperty -Path $registry -Name $Name
}
I propose to add a readonly block to initialize shared variables on a phase can be triggered by tab completion and before execution.
# Remove-StartupApplication.ps1
param(
[ArgumentCompleter({
param (
$commandName,
$parameterName,
$wordToComplete,
$commandAst,
$fakeBoundParameters
)
# now we share a same variable
# maybe we need a dedicated scope to distinct such variables
Get-Item $readonly:registry | ForEach-Object Property
})]
[Parameter(Mandatory)]
[string]$Name,
[switch]$AllUsers
)
readonly {
# this block should get evaluated on tab completion
# we may expose a event for PSReadline to trigger
if ($AllUsers) {
$registry = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run'
} else {
$registry = 'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run'
}
}
begin {
$ExePath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($ExePath)
}
end {
Remove-ItemProperty -Path $readonly:registry -Name $Name
}
Solution Proposal
The solution I can think of is to add a new named block readonly, variables declared in readonly block are immutable.
Such variables should be initialized on a phase can be triggered by tab completion and before execution, and should be accessible for attributes/scriptblock in attributes.
To avoid conflicts with external variables we should use explicit $readonly: scope to access variables declared in readonly block.
function foo {
param(
[ValidateSet($readonly:candidates)] # attributes are aware of readonly variables
[ValidateScript({ $_ -in $readonly:candidates })] # or access in scriptblock
[ArgumentCompleter({ & $readonly:completer })]
$foo
)
readonly {
$candidates = 'foo', 'bar'
$completer = {
# ...complex logic for parsing completion for native executables
# that you don't want to repeat in every ArgumentCompleter
}
}
begin {
if (-not $foo) {
$foo = $readonly:candidates | fzf --prompt 'pick one'
}
}
end {
$readonly:candidates = $null # ERROR: can't mutate readonly variables
$readonly:candidates[0] = 'baz' # ERROR: can't mutate readonly variables
}
}
Potential Problem
- if access the readonly variable within scriptblock for attributes like
ValidateScript, the error messages would be confusing for users:
The " $_ -in $candidates " validation script for the argument with value "baz" did not return a result of True. Determine why the validation script failed, and then try the command again.
- whether to prioritize readonly variables in attribute scriptblock to avoid ambiguity(should we add a
$readonly:scope?)
$foo = 1
function foo {
param (
[ArgumentCompleter({
# readonly variables should be explicit
# to avoid breaking change
$foo,$readonly:foo
})]
$foo
)
readonly {
$foo = 'foo'
}
}
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
No files, tests, or entry points are named. Start by reviewing the proposed readonly block and its interactions with tab completion, parameter attributes, scriptblocks, and execution phases. Done would require an agreed design and implementation for immutable shared variables, including scope access and mutation behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- powershell
- Domain
- cli
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100