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

RFC0003-Lexical-Strict-Mode comments #7

Open
lzybkr opened this issue Feb 26, 2016 · 11 comments
Open

RFC0003-Lexical-Strict-Mode comments #7

lzybkr opened this issue Feb 26, 2016 · 11 comments

Comments

@lzybkr
Copy link
Member

lzybkr commented Feb 26, 2016

Use this issue to comment on this RFC: https://github.com/PowerShell/PowerShell-Language-RFC/blob/master/1-Draft/RFC0003-Lexical-Strict-Mode.md

@KirkMunro
Copy link
Contributor

I use strict mode religiously in pretty much every module and script I create. This helps me identify bugs that may otherwise not be apparent until after I ship the module or script, and it encourages me to write more robust code.

For the modules I publish (and I'll focus on modules since I don't publish many scripts), I simply invoke Set-PSStrictMode -Version Latest at the top of the psm1 file, knowing that it sets me up for strict mode throughout my module. Unfortunately this dependency means I would be against the Change Set-StrictMode alternate proposal because I would have to redo every module I have in order to get the same benefit I get today.

It sounds to me like the goal here is to be able to invoke other PowerShell code that isn't designed to run in strict mode without generating errors while still getting the benefits of strict mode in your own code. I don't think lexical strict mode is the right way to provide this. Instead, maybe it would be better to provide syntax allowing people who use strict mode to be able to easily invoke other PowerShell logic with strict mode disabled/lowered to another level without affecting the rest of their code. That leaves Set-StrictMode working as it does today, as well as Set-StrictMode -Off, both of which are really easy to use, as well as for those scenarios where you're calling into code that you don't manage (and that therefore may not support strict mode). With that, I have another alternate proposal.

Alternate Proposal

Extend Set-StrictMode

Add an additional optional ScriptBlock parameter to Set-StrictMode, as follows:

Set-StrictMode -Version <version> [[-ScriptBlock] <ScriptBlock>] [<CommonParameters>]

Set-StrictMode -Off [[-ScriptBlock] <ScriptBlock>] [<CommonParameters>]

When invoking Set-StrictMode using the first parameter set without the optional -ScriptBlock parameter, it would function exactly as it does today. If, however, you passed in a ScriptBlock to the optional -ScriptBlock parameter, the command would store the current strict-mode level, set the strict-mode level to the requested level, invoke the script block in the current scope, and then reset the strict-mode level back to the original level.

The second parameter set would function in a similar fashion. Without the optional -ScriptBlock parameter, Set-StrictMode -Off would turn strict mode off in the current scope. With the optional -ScriptBlock parameter included, Set-StrictMode would store the current strict mode level, turn strict mode off, invoke the script block in the current scope, and then reset strict-mode back to the state (off or a specific level) it was in before the script block was invoked.

This proposal doesn't introduce new syntax other than an additional parameter on Set-StrictMode. It allows Set-StrictMode to function as it does today while also allowing script/module authors familiar with Set-StrictMode to be able to temporarily set the level they want within a script block they are about to invoke, so that they can call commands or script blocks that are not ready for strict mode without issue.

@nightroman
Copy link

Just a thought.

using strict

can be done as

#using strict

so that it can be used in later versions without breaking earlier versions.

@joeyaiello joeyaiello changed the title RFC003-Lexical-Strict-Mode comments RFC0003-Lexical-Strict-Mode comments Mar 25, 2016
@joeyaiello
Copy link
Contributor

Good feedback here. One thing that we want to be clear about is that we're not changing the existing behavior of Set-StrictMode but adding new behavior with the using strict syntax. @BrucePay: "I wanted to be clear the former happens at runtime while the latter happens at parse-time."

The reason that using strict is useful is because it won't impose strict mode on code outside your lexical block (e.g. outside of a script scope), so you can validate that your code is strict mode clean without worrying about the behavior of other modules, scripts, or functions.

@KirkMunro Given the above, can you explain why you're interested in the negative case of dropping out of strict mode for a single script block? In what scenario is this useful?

Open items:

  • Scenario for "negative case"
  • Concern that using (as opposed to #using) will break on older versions of PS

@DerpMcDerp
Copy link

The most common negative case scenario is that you put Set-StrictMode -Version latest at the top of the script but then selectively disable it in certain tiny regions of code to treat non-existent property access as benign.

Without Set-StrictMode -Off here, you have to resort to working around it with if ($null -ne $obj.psobject.Members.Item('Foo')) { $obj.Foo } which is chatty, error prone, and orders of magnitude slower.

If PowerShell had a pseudo "keyword member" construct like $obj.Foo.-or($null) that ran approximately the same speed as $obj.Foo with unstrict property access, it wouldn't be so bad.

@BrucePay
Copy link
Contributor

BrucePay commented Apr 1, 2016

WRT DerpMcDerp's comment, we should probably add support for the null-coalescing operator.?? and other "null-conditional operators" like the ?. operator from C#. See https://msdn.microsoft.com/en-us/library/dn986595.aspx Doing this should allow users to work around most of the "problems" introduced by the runtime Strict-Mode.

@KirkMunro
Copy link
Contributor

@joeyaiello I was misunderstanding the intent. My comments were based on thinking it would just happen at runtime. The suggestions @BrucePay made about having strict checking at parse time would be great, as would null-coalescing and null-conditional operators (as would the conditional ?: operator while you're at it).

With this idea being about parse-time checking though, I guess I'm a confused by the idea of enabling parse-time checking for certain issues that are ignored by default by modifying the file itself. In my mind, that's more of an IDE feature where you can throttle the warning level used during compilation. If you have to put it in the file though, my preference would be for #using over using. Otherwise it will just be a feature that either (a) sits on the shelf for a long time or (b) one that I create an extension for (VS Code or ISE) to remove the using statement before shipping for downlevel versions.

@joeyaiello
Copy link
Contributor

@PowerShell/powershell-committee has been working to drive down our RFC debt. Here are the notes that resulted out a meeting on this one:

  • Let's add a parameter to Set-StrictMode instead of using using
  • Should be hidden behind a feature flag for some time
  • We agree that Set-StrictMode -Off should turn off whatever strict mode is enabled
    • Caveat here is that lower lexical script blocks shall not disable
      global strict mode above them
  • Agreed that we should punt the module scope question
    • We don't know that there's any real pain to just putting
      Set-StrictMode -Lexical at the top of a .psm1
  • No strong feelings on the parameter name right now,
    but we don't have any great ideas
    • -NoInheritance? -Lexical?

@lzybkr
Copy link
Member Author

lzybkr commented Nov 12, 2018

To be clear here - my proposal was for parse time checks. Is the @PowerShell/powershell-committee thinking lexical checking should occur at runtime?

Runtime checks have definite downsides:

  • Performance - a lexical check is only necessary once, but at runtime. So either:
    • Check every time a variable is accessed
    • Introduce more complexity to do the check just once
  • Complexity - there is no notion of lexical scoping outside the parser today, so runtime scoping becomes more complicated.

@joeyaiello
Copy link
Contributor

@PowerShell/powershell-committee talked some more. We agreed that there is value in having a parse-time check (fail fast, ability to do more parse time checks, etc.), but those don't seem to help with the motivation outlined in the RFC (namely, that calling other people's scripts which fail strict mode won't be impacted by setting strict mode from within a script/module).

We had additional discussion and disagreement around whether the original motivation should be addressed as a new parameter on Set-StrictMode vs. using strict. Ultimately though, we agree with @lzybkr 's point about complexity, and don't think that we should implement this within Set-StrictMode.

Given that, the next steps on this RFC should be to extend the motivations to address the additional benefits of a parse-time using strict.

@mklement0
Copy link
Contributor

@DerpMcDerp: Good point re selective bypassing of strict-mode checks; there's now a feature request to implement the null-conditional (null-soaking) feature (and others) that @BrucePay references: PowerShell/PowerShell#3240

@joeyaiello
Copy link
Contributor

Setting this as up-for-grabs assuming that anyone who is interested will speak with us first to make sure that their implementation will meet our discussion's requirements per the above.

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

No branches or pull requests

7 participants