X Tutup
Skip to content

Stop setting $? to true for subpipelines and subexpressions#11040

Merged
daxian-dbw merged 14 commits intoPowerShell:masterfrom
rjmholt:dollarhook-subpipelines
Nov 15, 2019
Merged

Stop setting $? to true for subpipelines and subexpressions#11040
daxian-dbw merged 14 commits intoPowerShell:masterfrom
rjmholt:dollarhook-subpipelines

Conversation

@rjmholt
Copy link
Collaborator

@rjmholt rjmholt commented Nov 11, 2019

PR Summary

This PR alters the way we compile subpipelines (...), subexpressions $(...) and array expressions @() so that $? is not automatically true after them in the pipeline, but instead depends on the pipeline or statements they executed.

I've added tests for the various behaviours of this, plus some extra tests for pipeline chain operators, which this aids the UX of.

I've structured my changes by commit, so you'll probably find it easier to read this PR from commit to commit.

PR Context

In #9849, the && and || operators were introduced, but currently suffer from the implementation of $?. Specifically:

Write-Error "Bad" || Write-Output "Hi" # Outputs "Hi"

(Write-Error "Bad") || Write-Output "Hi" # Outputs only the error

This makes pipeline chain operators hard to use insofar as they can't be rearranged conveniently by means of parentheses.

In this PR, we change the implementation so that expression-only pipelines only have $? forcibly set when they are a pure value, expressions that actually execute their commands with $? set by the subpipeline.

Further considerations

  • This PR likely requires an RFC, which I can begin authoring immediately and will link back here
  • Calling Write-Error from within another function still has that function leaving $? as true. I looked into changing that behaviour briefly and it would be fairly complicated.
  • This PR doesn't try to expose new mechanisms for cmdlets to set $?

As a final note, looking into how to change this, it seems that while this behaviour may or may not have been originally intended, it occurs because we fix an assumption where all expressions in the pipeline are treated like pure expressions, which are optimised to be evaluated without the pipeline so need a $? = $true added after them. So theoretically this change also is a small (very small) performance improvement.

PR Checklist

@rjmholt rjmholt requested a review from daxian-dbw as a code owner November 11, 2019 22:48
@rjmholt rjmholt added WG-Engine core PowerShell engine, interpreter, and runtime Breaking-Change breaking change that may affect users CL-BreakingChange Indicates that a PR should be marked as a breaking change in the Change Log labels Nov 11, 2019
@rjmholt rjmholt force-pushed the dollarhook-subpipelines branch from d6d8a55 to 58a5652 Compare November 11, 2019 22:55
@rjmholt rjmholt added the Review - Committee The PR/Issue needs a review from the PowerShell Committee label Nov 11, 2019
@SteveL-MSFT
Copy link
Member

@rjmholt don't start writing a RFC for this, I believe after @PowerShell/powershell-committee review, it'll just be an update to your existing RFC

@vexx32
Copy link
Collaborator

vexx32 commented Nov 12, 2019

@rjmholt does this also affect the behaviour of @() array subexpressions? 🤔

@rjmholt
Copy link
Collaborator Author

rjmholt commented Nov 12, 2019

@rjmholt does this also affect the behaviour of @() array subexpressions? 🤔

Not currently. I can add tests so we can establish what the behaviour is and then should be.

@rjmholt
Copy link
Collaborator Author

rjmholt commented Nov 13, 2019

@vexx32 @KirkMunro are there any other expressions you can think of that could conceivably contain a statement?

@KirkMunro
Copy link
Contributor

@vexx32 @KirkMunro are there any other expressions you can think of that could conceivably contain a statement?

Brackets, array enclosures, subexpressions, and anonymous functions (script blocks that are dot-sourced or invoked) are the only things that come to mind for me.

@vexx32
Copy link
Collaborator

vexx32 commented Nov 13, 2019

Yeah that's all I got, I think that about covers all the things we can do. Thanks for digging into this, Rob! 😊 💖

@SteveL-MSFT SteveL-MSFT removed the Review - Committee The PR/Issue needs a review from the PowerShell Committee label Nov 14, 2019
@SteveL-MSFT SteveL-MSFT added the Committee-Reviewed PS-Committee has reviewed this and made a decision label Nov 14, 2019
@SteveL-MSFT
Copy link
Member

@PowerShell/powershell-committee reviewed this and agree this is the correct behavior of $? although it is a breaking change but unlikely to impact existing users

/// <returns>True is the compiler should add the success setting, false otherwise.</returns>
private bool MustSetSuccessAfterEvaluating(StatementAst statementAst)
{
// Simple overload fan out
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd remove the comment.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wanted to explain why this method really exists here -- it doesn't do anything itself, it's just for type resolution

@rjmholt
Copy link
Collaborator Author

rjmholt commented Nov 14, 2019

One case I just thought of: "$(Write-Error "Bad")"; $?. Not sure what the right behaviour there is.

Think for now we should leave it. Small (and strange) enough to address later.

@vexx32
Copy link
Collaborator

vexx32 commented Nov 14, 2019

I would be perfectly happy to just set $? to "undefined" at that point tbh Rob 😂

@KirkMunro
Copy link
Contributor

KirkMunro commented Nov 14, 2019

One case I just thought of: "$(Write-Error "Bad")"; $?. Not sure what the right behaviour there is.

If you're embedding the results of a subexpression inside of a string, my initial reaction is that the outermost string-building should influence dollar-hook as it does now, because the string still gets built in that case, and that's what $? is checking.

That said, should a scalar or string value ever influence dollar-hook? There isn't much value in that.

@rjmholt
Copy link
Collaborator Author

rjmholt commented Nov 15, 2019

If you're embedding the results of a subexpression inside of a string, my initial reaction is that the outermost string-building should influence dollar-hook as it does now, because the string still gets built in that case, and that's what $? is checking.

Given that the string value is returned, I very much agree. Have added tests for that.

Copy link
Member

@daxian-dbw daxian-dbw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@daxian-dbw daxian-dbw merged commit ad12b14 into PowerShell:master Nov 15, 2019
@iSazonov iSazonov added this to the 7.0.0-preview.6 milestone Nov 16, 2019
@ghost
Copy link

ghost commented Nov 21, 2019

🎉v7.0.0-preview.6 has been released which incorporates this pull request.:tada:

Handy links:

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

Labels

Breaking-Change breaking change that may affect users CL-BreakingChange Indicates that a PR should be marked as a breaking change in the Change Log Committee-Reviewed PS-Committee has reviewed this and made a decision WG-Engine core PowerShell engine, interpreter, and runtime

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants

X Tutup