Powershell: `return` on the RHS of an assignment ignores the assignment

Created on 9 Jul 2020  路  13Comments  路  Source: PowerShell/PowerShell

Note: This may be an exotic scenario that is easily avoided (no reason to ever use return this way), but I just came across it on Stack Overflow, and the behavior is surprising and unhelpful.

Steps to reproduce

# The assignment is *ignored* due to `return`, and the output goes straight to the success output stream.
$var = return 'foo'

$var | Should -BeExactly 'foo'

Expected behavior

The test should succeed.

Actual behavior

The test fails, because the assignment is ignored (the variable isn't even created) due to use of return.
The output goes straight to the success output stream and therefore prints to the display here.

Environment data

PowerShell Core 7.1.0-preview.5
Issue-Question

Most helpful comment

The RHS is executed before any assignment happens. Works the same as any other flow control statement like $a = throw/$a = continue. Probably should have been a parse error when assignments started allowing statements on the RHS, though I'm not sure it'd be worth doing now. (Edit: wasn't a thing) (Edit 2: I don't know what's real anymore) Maybe a PSSA rule?

All 13 comments

The RHS is executed before any assignment happens. Works the same as any other flow control statement like $a = throw/$a = continue. Probably should have been a parse error when assignments started allowing statements on the RHS, though I'm not sure it'd be worth doing now. (Edit: wasn't a thing) (Edit 2: I don't know what's real anymore) Maybe a PSSA rule?

As far as I know, assignment has always allowed full statements on the RHS. Because of this arrangement of the grammar, it would be very difficult, if not impossible, to turn this into a parse error. If nothing else, it would turn the RHS of assignments into a strange and confusing subset of the allowed statement grammar.

I'd say this is most like the old func_call(i++, i++) in C. It's syntactically allowed, but semantically not a good idea.

Thanks, @SeeminglyScience and @rjmholt - I'm personally happy with a "won't-fix" / "as-designed" classification , but I wanted the potential pitfall recorded.

Perhaps a candidate for the docs wiki?

I've updated the SO answer based on the feedback, so I'm happy to close this.

As an aside, @rjmholt: there is a second answer there that summarizes (and links to) our discussion in #10967 (using statements in pipelines / as expressions).

As far as I know, assignment has always allowed full statements on the RHS.

I could have sworn there was a time back in the dark ages of v2 or 1 where you couldn't have an if statement on the RHS... Maybe I'm thinking of return statements? 馃し anyway thanks for the correction 鉂わ笍

I could have sworn there was a time back in the dark ages of v2 or 1 where you couldn't have an if statement on the RHS

@SeeminglyScience You are right, and it was relaxed to allow statement on the right hand side of assignment in v3.
A parsing error is possible by semantic checks, but may not be worth the effort.

Hmm... I just tried $var = if ($true) { 'yay' } and $var = foreach ($i in 1..10) { $i } in v2, and it worked.

However, something related is indeed broken, all the way up to v5.1 (fine since v6), although the scenario is very specific:

# Breaks in *Windows PowerShell* - OK in PowerShell Core.
@{
  Foo = if ($true) { "yes" } # Value is an `if` statement that LACKS AN `else` and there's NO OTHER ENTRY on the SAME LINE
  Bar = 'Baz' # !! Any key AFTER triggers the error
}

@SeeminglyScience You are right, and it was relaxed to allow statement on the right hand side of assignment in v3.
A parsing error is possible by semantic checks, but may not be worth the effort.

See that's what I thought but then:

Hmm... I just tried $var = if ($true) { 'yay' } and $var = foreach ($i in 1..10) { $i } in v2, and it worked.

I tried it too with -verison 2 and it worked. I know there are some scenarios where -version 2 doesn't work exactly the same but I wouldn't have thought this would be one. You know if it was back ported? or maybe a change between 1 and 2?

At least I know I'm not crazy 馃榾

I know there are some scenarios where -version 2 doesn't work exactly the same

That's good to know (-version 2 is what I used too) - would have never occurred to me.

That's good to know (-version 2 is what I used too) - would have never occurred to me.

Full disclosure, that's what I've heard. I don't remember anything specific or having ran into anything personally (though I also don't use it super often) so ymmv

Hmm... I just tried $var = if ($true) { 'yay' } and $var = foreach ($i in 1..10) { $i } in v2, and it worked.

Ah, then I must remember it wrong. It could be a v1 -> v2 change. I doubt it would be ported back to v2 if it was done in v3, as v3 was a huge rewritten of a lot stuff.

However, something related is indeed broken, all the way up to v5.1 (fine since v6), although the scenario is very specific:

I think this one was fix by https://github.com/PowerShell/PowerShell/pull/7002

Thanks, @daxian-dbw.

Can you tell us definitely if there can ever be a difference between running a later version with -version 2 and a stand-alone v2 version and, if so, what those difference are?

I don't think there is any difference between running a stand-alone v2 version and running powershell -v 2.
The reason to have powershell -v 2 was that there were breaking changes introduced in v3 and we needed a way for users to keep using v2 without worrying about anything broken. So by definition, it shouldn't allow any difference.

I believe the v2 assemblies that are in-box for powershell -v 2 to work were just a redistribution of those from a stand-alone v2 version. So, more precisely, there shouldn't be any difference code-wise.

Was this page helpful?
0 / 5 - 0 ratings