Open iRon7 opened 4 years ago
https://github.com/PowerShell/PowerShell/issues/6467 tries to give a comprehensive overview of the current behavior with respect to arguments in command parsing mode - however, it doesn't cover the hashtable-key issue (see below).
about_Quoting_Rules
is probably the best place to document this, though it is currently being discussed in the larger context of parsing modes in https://github.com/MicrosoftDocs/PowerShell-Docs/issues/3440
As for use of unquoted key names in hash tables:
Without having looked at the source code, my understanding is as follows:
If a key is a syntactically valid number literal, it is used as a number - including with suffixes such as u
(U
) for [uint32]
and binary multiplier suffixes such as kb
, as well as hex. numbers (e.g., 0x10
) or numbers in exponential notation (e.g., 1e2
- , it is used as a number (this explains the 2U
key turning into 2
of type System.UInt32
in your example).
If a key starts with a digit, but is otherwise not a syntactically valid number literal, the hashtable definition fails.
DecimalDigitNumber
(Nd
) Unicode category, which includes characters such as ๐
(THAI DIGIT ZERO, U+0E50
)Otherwise, it is interpreted as a string, but parsing only succeeds if the token is limited to a sequence of the following characters (these seem to be the same that can be used in variable names without needing to enclose the name in {...}
- see the about_Variables
help topic's Variable Names that Include Special Characters section):
Characters from the following Unicode categories (defined in .NET as enumeration System.Globalization.UnicodeCategory
the two-letter shorthands listed in parentheses can be used with \p{<shortCategoryName>}
in regular expressions):
UppercaseLetter
(Lu
)
LowercaseLetter
(Ll
)
TitlecaseLetter
(Lt
)
ModifierLetter
(Lm
)
OtherLetter
(Lo
)
DecimalDigitNumber
(Nd
) - except as the first character (variable names don't have this restriction)
_
(underscore, the only allowed symbol)
To put it in terms of guidance:
Quote your hash-table keys, if:
they should be strings but happen to start with a digit.
they are strings that contain whitespace or a symbol other than _
@mklement0, thank you for the comprehensive information, it is very helpful.
It's worth pointing out that this same advice applies whenever you're interacting with a hashtable -- even when you're calling $hashtable.Add(
or getting or setting via dot notation or indexing. I.e.:
$hashtable[2u] = "UInt"
$hashtable.2u
Also worth noting is that good syntax highlighting (such as at the prompt in PSReadline) will make the distinction really obvious:
PowerShell allows for unquoted strings as shown in the Style-Guide/Naming-Conventions:
But there are limitations to using unquoted strings as e.g. spaces are not allowed in an unquoted value and will obviously fail if not quoted (with either single or double quotes, see the related issue: #63):
Besides using unquoted strings in argument values, unquoted strings are common (best practice?) in hash tables keys. Hash tables are major objects in PowerShell along with PSCustomObjects which are in fact constructed from a hash table. Hash tables are also used for things like splatting and PowerShell Data files.
As with argument values, the use of unquoted hash table keys is limited to certain characters, as e.g.:
Will cause an error:
In some cases there are no errors but pitfalls, like:
AFAIK, there is no clear definition of when I should use quoted keys (or argument values) or when I might not. In other words: which characters are allowed for unquoted strings (or: which characters are not allowed for unquoted strings)? It is also not described in About Quoting Rules or in About Special Characters (Assuming I am right, should I created a separate documentation issue at the PowerShell Team?)
So usually I use quotes on a trial-on-error bases or pro-actively on a better-safe-than-sorry bases. But that could cause some inconsistency in defining the best (readable) practice to resolve the above error:
Or:
I am especially concerned with this writing style / best practice issue because I am maintaining a ConvertTo-Expression script. Although the code might not follow the styling guidelines (yet), I am committed to follow them for the expression it outputs as much as possible. For this project, I got the issue request: Remove quotes in HashTables Keys when possible and looking for some documented guidance.