Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unquoted strings #146

Open
iRon7 opened this issue Jun 19, 2020 · 3 comments
Open

Unquoted strings #146

iRon7 opened this issue Jun 19, 2020 · 3 comments

Comments

@iRon7
Copy link

iRon7 commented Jun 19, 2020

PowerShell allows for unquoted strings as shown in the Style-Guide/Naming-Conventions:

# Instead write:
Get-Content -Path (Join-Path -Path $PSScriptRoot -ChildPath README.md)

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):

# Wrong:
Get-Content -Path (Join-Path -Path $PSScriptRoot -ChildPath READ ME.md)

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.:

# Wrong:
$Options = @{
    Margin    = 2
    Padding   = 2
    Font-Size = 24
}

Will cause an error:

Line |
   4 |      Font-Size = 24
     |          ~
     | Missing '=' operator after key in hash literal.

In some cases there are no errors but pitfalls, like:

$Hashtable = @{ 
    U2 = 'String'
    2U = 'UInt32'
}
$Hashtable.keys
2
U2

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:

$Options = @{
   Margin      = 2
   Padding     = 2
   'Font-Size' = 24
}

Or:

$Options = @{
   'Margin'    = 2
   'Padding'   = 2
   'Font-Size' = 24
}

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.

@mklement0
Copy link

mklement0 commented Jul 6, 2020

PowerShell/PowerShell#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 MicrosoftDocs/PowerShell-Docs#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.

    • Note: digit refers not just to the Latin decimal digits, but to all digits in the 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):


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 _

@iRon7
Copy link
Author

iRon7 commented Jul 7, 2020

@mklement0, thank you for the comprehensive information, it is very helpful.

@Jaykul
Copy link
Member

Jaykul commented Oct 17, 2020

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:
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants