When running a cmdlet, the parameter names don't have to be written out in full as long as the text is enough to uniquely identify one parameter, e.g.
Group-Object -NoElement
Group-Object -N # only -NoElement begins with N
Export-Csv -notype # binds to -NoTypeInformation
Get-ChildItem -P # not enough text to identify one parameter, throws an exception
Get-ChildItem : Parameter cannot be processed because the parameter name 'P' is
ambiguous. Possible matches include: -Path -PipelineVariable -LiteralPath.
I would like that behaviour for operators as well. e.g.
$text -replace 'a', 'b'
$text -r 'a', 'b' # -r would be -replace
$text -m 'abc' # -m would be -match
$text -j '.' # -j would be -join
$text -s ',' # -s is not enough to uniquely identify anything
# currently it throws an exception
Unexpected token '-s' in expression or statement.
# It could stay the same, or instead throw a similar message to the parameter matching:
Unexpected token '-s' in expression or statement. (Possible operator matches include: -shl, -shr, -split)
The intent would be like aliases - for interactive / shell use, not recommended in longer scripts.
There is already a precedent for a single character operator of this form with -f, although this change would not necessarily mean "single characters", just "short enough to be unique".
Currently, writing a partial operator name is an error, so initial thoughts are that this change would not clash with any existing feature, or break any existing code. It would mean new code written with variable length operator names could limit the scope for adding future operators without clashes. The big wins of this change are -replace, -join, -split, -match and there is little benefit in writing -o instead of -or and similar. Because of this, another possible version of this request would be to make explicit operator overloads -r, -j, -sp, -m which shorten just those operators, and no other variations are possible (-repl would fail). This version would reduce possible clashes with future operators. However in the full change, the case sensitive/insensitive variants also map nicely to -ir, -cr, -isp, -csp, -im, -cm and with fixed overloads they wouldn't.
The change to implement might be as simple as changing the way operators are looked up in the tokenizer scanparameter() method ('// Scan either a parameter or an operator') so that instead of using only TryGetValue() to look for a match, a failed lookup would test all the dictionary keys with a .startswith string test (I don't think wildcard matching would be relevant). Pseudocode:
if (s_operatorTable.TryGetValue(str, out operatorKind))
{
return NewToken(operatorKind);
}
//becomes
if (s_operatorTable.TryGetValue(str, out operatorKind))
{
return NewToken(operatorKind);
}
else
{
KeyValuePair<string, tokenKind> partialOperator = s_operatorTable.SingleOrDefault( x => x.Key.StartsWith(str, [case insensitive startswith]));
if (partialOperator is not null)
{
return NewToken(partialOperator.Value);
}
}
Generating the helpful error message with possible matches would be harder, but keeping with the same Unexpected token: -s would be still valid. In this way the normal full operator name lookup would be the same speed, there would only be extra work scanning the dictionary names if that lookup failed.
You already cannot write Get-Help -split, so that would not change for Get-Help -sp, it could be added to about_Operators as a mention of partial matching, or added specifically to about_Comparison_Operators, about_Split and about_Join.
Longer term, the most annoying part is $testMessage = $testMessage -replace 'a', 'b' having the variable name doubled and the long operator. I would like to see a shorter way of writing this pattern:
$testMessage = $testMessage -replace 'a', 'b'
# this change, syntactic sugar for partial operator name matching:
$testMessage = $testMessage -r 'a', 'b' # -r operator maps to -replace
# future change, pattern of $x += 1, $x *= 1 generalised to $x -operator= ___
$testMessage -replace= 'a', 'b' #-replace= acts exactly like the pattern +=
# and saves writing the variable/expression twice
$testMessage -r= 'a', 'b' # combination of both -r and -operator= makes -r= possible
# interactively
$x -r= ' ' is a much shorter "remove spaces" than $x = $x -replace ' '
That would make a nice addition to PowerShell's elastic syntax for interactive use.
To state the perhaps obvious, PSScriptAnalyzer would have to add a rule to warn of such use in _scripts_.
I don't think explicit single-letter overloads are a good idea, however, as they would effectively close the door on introducing new operators that start with the same letter.
(It doesn't _technically_ prevent them, but I think it would invite too much confusion.)
I disagree. Primarily for the reason @mklement0 states:
they would effectively close the door on introducing new operators that start with the same letter(s)
Plus it would make PS script that much harder to read IMO. Yeah, you could add a rule PSSA but you can't make folks use PSSA or enforce that rule. Modern console and editors provide auto-completion so typing -r and pressing tab` eases the typing load.
@rkeithhill:
I get the concern about readability, but the end of the elasticity spectrum we're talking about here is _throwaway_ code that you can _type as quickly as possible_, for one-off _command-line_ use.
@HumanEquivalentUnit's suggestion is simply about implementing the existing elastic syntax more comprehensively; to extend it from not just applying to _parameters_ to _operators_ too.
The down-sides of PS elastic syntax are _invariably_:
However, in the proper context (as described), elastic syntax is a useful feature that enables:
Tab-completion, as helpful and invaluable as it is in general, gets in the way of both these features.
If we agree that elastic syntax is a worthwhile feature, the challenge to focus on is to reconcile its use with _non_-throwaway (maintainable) uses and to how to best manage and facilitate the _transition_ from throwaway to maintainable code.
The trouble spots are:
How do we translate existing throw-away code into maintainable code:
-Expand to -ExpandProperty in the context of Select-Object).-r -> -replace) would go a long toward allowing throwaway code and maintainable code to coexist and to promote the former to the latter on demand.How do we prevent _running_ scripts that use elastic (throwaway) syntax / aliases?
How do we prevent sample code from using elastic syntax, possibly leading the uninitiated to think its use is safe in scripts too? (That problem already exists with respect to parameter names and aliases).
I disagree. Primarily for the reason @mklement0 states:
they would effectively close the door on introducing new operators that start with the same letter(s)
For reference, I'm wondering how often "introducing new operators" happened in PS history. Not counting @splatting or 3>&1 style operators which are not relevant to this, only the -operator form, it looks like:
-split, -join.-shl, -shr, -bnot, and -[c/i]in, -[c/i]notin.Are there any known, planned, suggested or requested new operators? I have searched the PowerShell UserVoice and GitHub issues, and found requests for the 'Bash &&' operator, a request for Perl's =~ which partially influenced this request and my longer term -replace= -> -r= comment, native ternary operator of a different syntax, a request for an exponentiation operator #3603 (which doesn't ask for this, but could plausibly be -pow, -power, -exp...).
That's not exhaustive, and the past is a few years whereas the future is forever, but it suggests there isn't a large set of operators trying to come into existence with possibly clashing names.
Unless someone wants to suggest a more dynamic approach overall:
New-BinaryOperator -Name pow -ScriptBlock {param($L, $R) [math]::Pow($L, $R)}
4 -pow 2
which really could cause a lot of clashes with variable length operator name resolution.
@mklement0
I get the concern about readability, but the end of the elasticity spectrum we're talking about here is throwaway code that you can type as quickly as possible, for one-off command-line use.
Code written at the command line often goes right into scripts (or into blog posts). You assume everyone is running PSSA and that is far from reality atm.
As for predicting the future in terms of new operators, who's to say. But IMO typing a few less characters (if for some weird reason you don't use tab completion), is not worth precluding the introduction of operators in the future with the desired name for that operator.
@HumanEquivalentUnit:
whereas the future is forever
Indeed. You never know. That's why closing doors should be avoided.
However, as syntax for _throwaway_ code (quick and dirty, on the command line), simply extending the current elastic syntax (-r works as shorthand for -replace, as long as no other -r* operator exists), as you first proposed, seems useful, and doesn't close any doors.
@rkeithhill
Code written at the command line often goes right into scripts (or into blog posts).
Understood, but that's the price you invariably pay for supporting elastic syntax.
There is an inherent, unresolvable tension between the abbreviated, potentially ambiguous (over time), one-off, quick-and-dirty (interactive shell) and the verbose, unambiguous, maintainable (programming).
The only way to _ensure_ that the realms are kept separate is to _prevent_ use of elastic syntax in scripts.
For backward compatibility, that probably won't happen by default, but an opt-in strict mode seems reasonable - I've added a suggestion to #2000.
As for help with _bridging_ the realms: That's where PSScriptAnalyzer / the PowerShell VSCode extension come in.
if for some weird reason you don't use tab completion
Not everyone will care about the following issues, but to me they make sense:
If I already know that having typed -r unambiguously indicates my intent:
I don't want to additionally have to type tab (which always also makes me pause mentally to check whether the expansion worked as expected)
I don't want to increase the length of my command line, which can matter when composing complex command (comprehension at a glance, navigating).
Of course, you could argue that elastic syntax shouldn't be supported at all, but, personally, I'd miss it, and I suspect I'm not the only one.
Don't see this as adding anything. Operators are, for the most part, small anyway and with tab completion you don't need to type that much.
I'm with Keith on this one
@RichardSiddaway:
If you always use tab completion, you're clearly not the target demographic for elastic syntax altogether.
For those that do care about and use elastic syntax, making it work more consistently and comprehensively seems worthwhile to me (even though operator names are comparatively shorter than parameter names).
There is an inherent, unresolvable tension between the abbreviated, potentially ambiguous, one-off, quick-and-dirty and the verbose (interactive shell), unambiguous, maintainable (programming).
The only way to ensure that the realms are kept separate is to prevent use of elastic syntax in scripts
And to force variable type annotations, fully-qualified command identification in the form Microsoft.PowerShell.Management\Get-ChildItem, array enumeration only to prevent any chance of indexing outside the bounds of the array (strict mode makes that an error, but it's still a runtime error), etc. etc.
Many things in PS are ambiguous until runtime, it already is up to the programmer "how much ambiguity they are willing to tolerate"; with that background, "ambiguous operator lookup" is only a tiny adjustment in the overall amount of ambiguity. I like @mklement0's approach of making a more clear and visible and automatically-checkable distinction between "casual" and "strict" PowerShell.
I am leaning a little away from "completely dynamic operator lookup" when four fixed operator aliases: -r, -m, -sp, -j which map to -replace, -match, -split, -join would be unambiguous, would not close doors for future operators beginning with those letters (if there was no lookup, then a fixed -r would never clash with a possible future operator -range), and would provide most of what I want from this change request, in a slightly more rigid way.
@HumanEquivalentUnit:
What you're asking for is _operator aliases_ (e.g., -r as a locked-in-forever, unambiguous alias of -replace), which would be the expression-mode analogs to command-mode _parameter aliases_ (e.g., -Args for -ArgumentList).
My initial thought was that parameter aliases are never _single-character_ names, but, as it turns out, that's not true, so I'm warming up to your idea:
For instance -f is an alias of -Force in the context of Remove-Job, even though in terms of elastic syntax alone, -f would be ambiguous, because there's both -Force and -Filter
It is the fact that it is an alias that makes it unambiguous, however.
(As an aside: This doesn't always work consistently at the moment: see #4739)
Note that supporting _both_ elastic syntax (unambiguous prefix matching) _and_ aliases for operators would be possible, just the way it already works for _parameters_.
Of course, some may object to introducing such terse aliases for operators, given that they'd have to be allowed in scripts too.
Also, there's currently a bit of a discoverability problem with respect to _parameter_ aliases - they don't show up in syntax diagrams, and Get-Help currently doesn't even list them with -Full switch, though the _online_ help topics already do (see https://github.com/PowerShell/PowerShell-Docs/issues/1638) - something that would also have to be solved for _operator_ aliases.
I've just realised that this partially exists in the way Where-Object has individual parameter sets, one for each comparison operator (help reference), to enable this shorthand form without the full scriptblock:
gci |? name -match abc
Because each operator is explicitly a cmdlet parameter here, in this context only they can be written with a partial name:
gci |? name -m abc
and parameter name resolution turns that into -match.
The two objections of "readability" and "future operators might change the way operator names resolve and break existing scripts" have already happened with some operators because of this case, including -m(atch), -li(ke), -cont(ains), -ili(ke), -cc(ontains) but not the focus ones of my request: -replace, -split, -join because they make no sense as parameters to filter on.
I made a proof of concept change, with the tokenizer.cs lookup code changed to be:
TokenKind operatorKind;
if (s_operatorTable.TryGetValue(str, out operatorKind))
{
return NewToken(operatorKind);
}
else
{
var partialOperatorMatches = s_operatorTable.Where( x => x.Key.StartsWith(str, StringComparison.OrdinalIgnoreCase));
if (1 == partialOperatorMatches.Count())
{
return NewToken(partialOperatorMatches.First().Value);
}
}
It does break tab completion for some situations I haven't properly traced yet, so a full change would have to be more involved, but it does work).

@HumanEquivalentUnit: What you're describing is the existing implementation of _elastic syntax_: Both Where-Object and ForEach-Object, since PSv3, accept _parameters_ (_argument-mode_ parsing) in lieu of a script block (_expression-mode_ parsing) to specify the filter / operation, and in the parameter form they're called _comparison statement_ and _operation statement_ respectively:
Elastic syntax means that any parameter name can be prefix-abbreviated, as long as the prefix _unambiguously_ identifies a parameter.
Elastic syntax inherently has both of the problems previously discussed:
lack of readability
lack of long-term stability
_That was a price that elastic syntax was always willing to pay_, in order to gain the benefits of being able to minimize typing for _interactive use_.
Elastic syntax is _not_ meant to lock in future-proof shorthands - by its very nature, it is only guaranteed to work at the moment of its invocation.
By contrast, in _argument mode_ it is _parameter aliases_ that lock in future-proof shorthands, such as
-Args for -ArgumentList for Start-Process or -m for -Match for Where-Object (but note that -Match is a _parameter_ here, not an operator).
Currently, there is no _expression-mode_ equivalent: there are no _operator aliases_ that would lock in
-m as an alias for the -match operator, for instance.
_Also, elastic syntax currently doesn't apply to expression-mode parsing at all._
In other words: What you're proposing is the introduction of _operator aliases_, which don't currently exist - and if they are introduced, each such alias would have to be implemented as an analogous _parameter alias_ for the corresponding Where-Object / ForEach-Object parameter, if it applies.
Separately - independently - elastic syntax could be extended to expression mode so as to apply to _operators_ too.
I hope that sufficiently clarifies the context.
As I've said: I personally like the idea, but it does mean that the less readable operator aliases such as -s, -j, and -m would also have to be permitted in _scripts_
(unless a strict mode is introduced that also prevents use of operator aliases in scripts; I definitely think there should be a strict mode that prevents _elastic syntax_ in a script).
Most helpful comment
@rkeithhill
Understood, but that's the price you invariably pay for supporting elastic syntax.
There is an inherent, unresolvable tension between the abbreviated, potentially ambiguous (over time), one-off, quick-and-dirty (interactive shell) and the verbose, unambiguous, maintainable (programming).
The only way to _ensure_ that the realms are kept separate is to _prevent_ use of elastic syntax in scripts.
For backward compatibility, that probably won't happen by default, but an opt-in strict mode seems reasonable - I've added a suggestion to #2000.
As for help with _bridging_ the realms: That's where PSScriptAnalyzer / the PowerShell VSCode extension come in.
Not everyone will care about the following issues, but to me they make sense:
If I already know that having typed
-runambiguously indicates my intent:I don't want to additionally have to type tab (which always also makes me pause mentally to check whether the expansion worked as expected)
I don't want to increase the length of my command line, which can matter when composing complex command (comprehension at a glance, navigating).
Of course, you could argue that elastic syntax shouldn't be supported at all, but, personally, I'd miss it, and I suspect I'm not the only one.