You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Do not require { ... } (curly braces) around variable names for null-conditional member access #14025
Note: This issue is just a reminder to reopen #11379 in order to have it revisited by the PowerShell committee; the willingness to do so was signaled in the Sept. '20 community call (see details below), but there was no follow-up, and leaving an issue in a closed state usually means that it falls through the cracks. There is clearly community interest in having this revisited, and the analysis that led to closing the issue is disputed.
Once #11379 is reopened, this issue can be closed.
Given that you indicated willingness to revisit this, please reopen the linked issue and re-tag it as Review - Committee.
As for your remarks that enclosing variable names in curly braces is a preexisting feature and that people object to having to use them in this case on aesthetic grounds:
I don't think anyone here isn't aware that {...}can and sometimes must be used to disambiguate variable names.
It is also not about aesthetics, it is primarily about not getting the expected behavior in manner that potentially fails quietly (depending on what strict mode is in effect), due to not expecting to have to use {...} in this case; a secondary concern is typing inconvenience.
Reacted by ili101, Kris Borowinski, ExE Boss, Thomas Nieto, Keith Hill, Maximilian Orsley, HumanEquivalentUnit, Paul B, swbbl, Dongbo Wang and 9 more
FWIW, if you use PowerShell script with ${var} syntax (not necessary with ? char) in combination with Terragrunt, it will fail. A workaround is to escape ${ with $$${ which is very misleading and looks ugly.
ALIENQuake A (subjectively) better workaround is using ($var)?.Member instead. Personally I prefer that syntax over ${var}?.Member anyway, assuming the only intention is to make ?. work.
Reacted by Michael Klement, Flavien MICHALECZEK and jbress
To be honest, this kind of did sway me on this issue a little bit, we still want to have a conversation and we can make it a priority in our next committee meeting. Someone did do the analysis on our behalf in the corpus and determined that there was 2 uses of the question mark in a variable name. I think it's something that we could possibly do as an experimental feature early in 7.2 [...] it's tricky [...] it's not a zero-cost thing [...] not a huge priority right now, so I don't want to guarantee that that's happening.
Priority is a separate issue, but I do hope this issue won't fall through the cracks, which seems to be a real possibility, given how the debate has unfolded (see timeline below).
To frame the issue in the context of the breaking-change debate:
The benefit of the change is: Without it, the utility of the new null-conditional access operators will be severely hampered, because users won't expect to have to enclose the variable name in {... } in order to use it; with Set-StrictMode -Version 1 or higher, you'll at least get an error (because $foo?.bar then requires the existence of ${foo?}), but with strict mode off the code will simply not do what users expect, as pointed out by @rkeithhill and acknowledged as a problem by you.
As for whose code will break due to the change: if the corpus is representative, virtually nobody's - see below.
As for Rob Holt (@rjmholt)'s syntax-change concerns: this is not a syntax change, but a semantic one: old code won't break during parsing, it'll simply behave differently - and since there is virtually no code like that in existence, this is a moot point.
It is closed on Aug 26, 2019 after the committee decides it would be too much of a breaking change, following analysis of the corpus. "there was quite a bit of usage of variable names ending with the question mark"
The community does their own analysis, with the heavy lifting performed by Thomas Nieto (@ThomasNieto); further analysis finds virtually no usage of variable names ending in ?: one(!) bona fide instance in the corpus, with the majority of the occurrences - limited to 8 files in total - showing mistaken usage of ? inside expandable strings (e.g., "Are you sure you want to kill $vParam?"), which implicitly makes the case for the requested change: users do not and should not expect ? to be usable in a variable name without {...}.
The issue is discussed again in the Nov 19 community call, where @SteveLee in essence repeats his arguments from the Sept. call, showing no awareness of the counterarguments that have been made, and notably repeating the claim "I think we did some research and there are people who use this, so we don't want to break them" and saying "I don't think this really that much of a pain point that we want to keep revisiting". Later in the call this is tempered by @joeyaiello's acknowledgement of the problem.
Needless to say, the above is liable to erode the community's confidence that its concerns and feedback are taken seriously.
Reacted by Mariusz Pawelski, Matěj Kafka, jantari, wisemoth and Anja Lea Brinkmann
Reacted by Maximilian Orsley, ALIENQuake, Thomas Nieto, Francis Mercier, Flavien MICHALECZEK and Matthew A Cargile
changed the title [-]Do not require { ... } around variable names for null-conditional member access[/-][+]Do not require { ... } (curly braces) around variable names for null-conditional member access[/+]on Dec 11, 2020
When I first discovered the Null-coalescing operators introduce in v7 I was initially pleased. That is until I started reading the ugly details and starting experimenting with this.
In my opinion, this is another example of being held back by prior bad design choices that just goes on to haunt us for evermore, instead of making a corrective breaking change. What value is there for being able to use a '?' in a variable name? It has next to no value but high restraining and detrimental impact. Why can't we have a breaking change that removes this? Having to use those {} just to appease variables names with a question mark is a case of the tail wagging the dog. Sure, there will be some code will be impacted. But if you document it well and SHOUT about it, make it easy for users to upgrade their code, possibly via a new new PSSA warning, then I think that would be better for all of us. The use of the {} really is aweful and should be fixed.
I'm experimenting with test code at the moment and have a test that refers to a PSCustomObject $_options, which contains nested members. I need to access $_options.Tags.From in a safe way.
Tags is known to never be null, but From is optional. So when you use coalescing, do you apply that to the whole path at once, or do you use the ?. on each sub member. When I try the latter (this scenario is missing from the help doc), it doesnt work because the sub member access is referenced independently, not as a member.
# no coalescing, this is ok, but potentially unsafe, if From doesnt exist (I think)if ($_options.Tags.From) {
# this doesnt work# => RuntimeException: The variable '$Tags' cannot be retrieved because it has not been set.#if (${_options}?.${Tags}.From) {
# this doesnt work# => The variable '$_options.Tags' cannot be retrieved because it has not been set.if (${_options.Tags}?.From) {
so what is the correct and safe way to coalesc the entire path from _options right down to From? And also, do the rules apply the same inside of a class method as opposed to a function or script?
...and the strange thing is this:
if ($_options.Tags.To) {
Write-Host"---> (PLAIN) TO: '$($_options.Tags.To)'"
}
else {
Write-Host"---> (PLAIN) TO: MISSING"
}
prints:
---> (PLAIN) TO: MISSING
and in fact this is the functionality I want, but I fear it is unsafe, but I dont know why. And if this works, why do we need the coalesc operator. I though the operator was introduced to prevent accessing a non existing member as in this case, from returning error, but return $null instead.
While using parentheses is always an option, no workaround is actually required in this case, because Tags is a property rather than a variable name, and the former, unlike the latter, aren't permitted to contain ?:
But to me this distinction between variable names and property names is yet another reason to never require {...} in combination with null-conditional access (?. / ?[]).
As an aside: what null-conditional access currently doesn't protect against is non-existence, as opposed to existence with value $null, even though these conditions are otherwise often interchangeable in PowerShell:
$_options.Tags3?.From # !! ERROR, because property doesn't *exist* - as opposed to *existing and being $null*.
Reacted by Plastikfan, Rain Sallow (/u/ta11ow), Maximilian Orsley, ExE Boss, Flavien MICHALECZEK, jantari and Emil Vissing
$_options.Tags3?.From # !! ERROR, because property doesn't *exist* - as opposed to *existing and being $null*.
I have a different opinion on this. By enabling StrictMode, you mean to catch the the cases where a non-existing member gets accidentally dereferenced at runtime, and that's what it does even with the null-conditional operator, isn't it?
The null-conditional operator is essentially a syntactic sugar of if ($null -eq target) { $null } else { target.member }, so I don't think it should suppress the "non-existing property" check enforced by the strict mode.
You may ask "why $_options.Tags2?.From doesn't error out given that From is a non-existing member?". That's because the From property doesn't get dereferenced at runtime -- the else block won't be evaluated.
This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.
microsoft-github-policy-service commented on Nov 16, 2023
This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.
microsoft-github-policy-service commented on Nov 16, 2023
This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.
Activity
[-]Feature Request[/-][+]Do not require { ... } around variable names for null-conditional member access[/+]ALIENQuake commentedon Nov 28, 2020
FWIW, if you use PowerShell script with ${var} syntax (not necessary with
?char) in combination with Terragrunt, it will fail. A workaround is to escape${with$$${which is very misleading and looks ugly.SeeminglyScience commentedon Nov 29, 2020
ALIENQuake A (subjectively) better workaround is using
($var)?.Memberinstead. Personally I prefer that syntax over${var}?.Memberanyway, assuming the only intention is to make?.work.mklement0 commentedon Dec 11, 2020
@joeyaello, thanks for showing awareness of the problem in the Nov 19 community call:
Priority is a separate issue, but I do hope this issue won't fall through the cracks, which seems to be a real possibility, given how the debate has unfolded (see timeline below).
To frame the issue in the context of the breaking-change debate:
The benefit of the change is: Without it, the utility of the new null-conditional access operators will be severely hampered, because users won't expect to have to enclose the variable name in
{... }in order to use it; withSet-StrictMode -Version 1or higher, you'll at least get an error (because$foo?.barthen requires the existence of${foo?}), but with strict mode off the code will simply not do what users expect, as pointed out by @rkeithhill and acknowledged as a problem by you.As for whose code will break due to the change: if the corpus is representative, virtually nobody's - see below.
As for Rob Holt (@rjmholt)'s syntax-change concerns: this is not a syntax change, but a semantic one: old code won't break during parsing, it'll simply behave differently - and since there is virtually no code like that in existence, this is a moot point.
Timeline:
The original request, Do not require { ... } around variable names for null-conditional member access #11379, is opened on Dec 17, 2019.
It is closed on Aug 26, 2019 after the committee decides it would be too much of a breaking change, following analysis of the corpus. "there was quite a bit of usage of variable names ending with the question mark"
A request to show the original analysis that the committee decision was based on is ignored.
The community does their own analysis, with the heavy lifting performed by Thomas Nieto (@ThomasNieto); further analysis finds virtually no usage of variable names ending in
?: one(!) bona fide instance in the corpus, with the majority of the occurrences - limited to 8 files in total - showing mistaken usage of?inside expandable strings (e.g.,"Are you sure you want to kill $vParam?"), which implicitly makes the case for the requested change: users do not and should not expect?to be usable in a variable name without{...}.A request to reopen the original issue on 24 Sep, after a discussion in the Sep 17 community call, is ignored.
This issue is opened on Nov 10, as a reminder to reopen the original one, along with addressing the arguments made by @SteveLee in the Sep 17 community call.
The issue is discussed again in the Nov 19 community call, where @SteveLee in essence repeats his arguments from the Sept. call, showing no awareness of the counterarguments that have been made, and notably repeating the claim "I think we did some research and there are people who use this, so we don't want to break them" and saying "I don't think this really that much of a pain point that we want to keep revisiting". Later in the call this is tempered by @joeyaiello's acknowledgement of the problem.
Needless to say, the above is liable to erode the community's confidence that its concerns and feedback are taken seriously.
[-]Do not require { ... } around variable names for null-conditional member access[/-][+]Do not require { ... } (curly braces) around variable names for null-conditional member access[/+]plastikfan commentedon Apr 21, 2021
When I first discovered the Null-coalescing operators introduce in v7 I was initially pleased. That is until I started reading the ugly details and starting experimenting with this.
In my opinion, this is another example of being held back by prior bad design choices that just goes on to haunt us for evermore, instead of making a corrective breaking change. What value is there for being able to use a '?' in a variable name? It has next to no value but high restraining and detrimental impact. Why can't we have a breaking change that removes this? Having to use those {} just to appease variables names with a question mark is a case of the tail wagging the dog. Sure, there will be some code will be impacted. But if you document it well and SHOUT about it, make it easy for users to upgrade their code, possibly via a new new PSSA warning, then I think that would be better for all of us. The use of the {} really is aweful and should be fixed.
I'm experimenting with test code at the moment and have a test that refers to a PSCustomObject $_options, which contains nested members. I need to access $_options.Tags.From in a safe way.
Tags is known to never be null, but From is optional. So when you use coalescing, do you apply that to the whole path at once, or do you use the ?. on each sub member. When I try the latter (this scenario is missing from the help doc), it doesnt work because the sub member access is referenced independently, not as a member.
assuming:
so what is the correct and safe way to coalesc the entire path from _options right down to From? And also, do the rules apply the same inside of a class method as opposed to a function or script?
...and the strange thing is this:
prints:
and in fact this is the functionality I want, but I fear it is unsafe, but I dont know why. And if this works, why do we need the coalesc operator. I though the operator was introduced to prevent accessing a non existing member as in this case, from returning error, but return $null instead.
PS, I'm using strict mode 1
ExE-Boss commentedon Apr 21, 2021
Plastikfan (@plastikfan) You need to use parentheses:
plastikfan commentedon Apr 21, 2021
Well if that works, why are we being bogged down and harrased into using ${}? What is the value of that, if we can just use ()?
ALIENQuake commentedon Apr 21, 2021
Plastikfan (@plastikfan) The point is to be able to use
$variable?syntax, without braces.plastikfan commentedon Apr 21, 2021
ALIENQuake, I know, I'm adding my 2 pence worth to get rid of the braces.
mklement0 commentedon Apr 21, 2021
Perhaps needless to say, Plastikfan (@plastikfan), I fully agree with your assessment.
While using parentheses is always an option, no workaround is actually required in this case, because
Tagsis a property rather than a variable name, and the former, unlike the latter, aren't permitted to contain?:But to me this distinction between variable names and property names is yet another reason to never require
{...}in combination with null-conditional access (?./?[]).As an aside: what null-conditional access currently doesn't protect against is non-existence, as opposed to existence with value
$null, even though these conditions are otherwise often interchangeable in PowerShell:plastikfan commentedon Apr 21, 2021
thanks Michael Klement (@mklement0)
morsley commentedon Apr 21, 2021
Michael Klement (@mklement0) yikes.. what a footgun of a decision
daxian-dbw commentedon May 1, 2021
I have a different opinion on this. By enabling
StrictMode, you mean to catch the the cases where a non-existing member gets accidentally dereferenced at runtime, and that's what it does even with the null-conditional operator, isn't it?The null-conditional operator is essentially a syntactic sugar of
if ($null -eq target) { $null } else { target.member }, so I don't think it should suppress the "non-existing property" check enforced by the strict mode.You may ask "why
$_options.Tags2?.Fromdoesn't error out given thatFromis a non-existing member?". That's because theFromproperty doesn't get dereferenced at runtime -- theelseblock won't be evaluated.5 remaining items
vexx32 commentedon May 3, 2021
If there is, I'm not seeing it at the moment. Thought there would have been though. #2798 is somewhat related, I suppose. Opened #15338 for that, ty.
microsoft-github-policy-service commentedon Nov 16, 2023
This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.
microsoft-github-policy-service commentedon Nov 16, 2023
This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.
microsoft-github-policy-service commentedon Nov 16, 2023
This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.
ThomasNieto commentedon Nov 16, 2023
This issue is waiting for the WG to reevaluate with update information.
microsoft-github-policy-service commentedon Nov 23, 2023
This issue has been marked as "No Activity" as there has been no activity for 6 months. It has been closed for housekeeping purposes.
jantari commentedon Nov 23, 2023
Thomas Nieto (@ThomasNieto) commented on this, I don't feel like it should have been closed given that that was "activity"?
vaind commentedon Feb 23, 2024
Can someone reopen this issue? The bot has obviously bugged out. Or should we create another issue to reopen an issue to reopen an issue? 😬
jantari commentedon Feb 23, 2024
I believe the intent with the great issue purging of 2023 was for us to re-open new issues where needed.
I did that with #20705 so now that issue is in limbo again just like the original #8751 before it 😄👍
vaind commentedon Feb 23, 2024
that seems to be a different issue?
jantari commentedon Feb 23, 2024
Yes, but it is an example of an issue that was also closed by the bot and we've had to create a new one.