6

The following powershell script

"one","two","three" | % { "$(($l++)): $_" }

will print

1: one
2: two
3: three

However, after remove the bracket around $l++

"one","two","three" | % { "$($l++): $_" }

it will print

: one
: two
: three
JasonMArcher
  • 13,296
  • 21
  • 55
  • 51
ca9163d9
  • 24,345
  • 44
  • 175
  • 352

4 Answers4

12

This is because $l++ is a voidable statement. In powershell certain types of expressions, when used as statements, are not displayed. Voidable statements include assignments and the increment/decrement operators. When they are used in an expression, they return a value, but when they’re used as a standalone statement, they return no value. It is very well explained in Windows Powershell in Action by Bruce Payette:

The increment and decrement operators were almost not included in PowerShell because they introduced a problem. In languages such as C and C#, when you use one of these operators as a statement: $a++ nothing is displayed. This is because statements in C and C# don’t return values. In PowerShell, however, all statements return a value. This led to confusion. People would write scripts like this:

$sum=0
$i=0
while ($i -lt 10) { $sum += $i; $i++ }
$sum

and be surprised to see the numbers 1 through 10 displayed. This was because $a++ returned a value and PowerShell was displaying the results of every statement. This was so confusing that we almost removed these operators from the language. Then we hit on the idea of a voidable statement. Basically, this means that certain types of expressions, when used as statements, are not displayed. Voidable statements include assignments and the increment/decrement operators. When they are used in an expression, they return a value, but when they’re used as a standalone statement, they return no value. Again, this is one of those details that won’t affect how you use PowerShell other than to make it work as you expect. (source: Windows Powershell in Action)

jon Z
  • 14,930
  • 1
  • 31
  • 35
4

I believe this was a design decision made by the PowerShell team to avoid surprises due to PowerShell outputting return values. Many C/C# folks would expect the following function to only output 1 not @(0,1).

function foo {
  $i = 0
  $i++
  $i
}

So the statement form $i++ doesn't output the value of $i before it is incremented. If you want that behavior, PowerShell allows you to get that behavior by putting the increment (or decrement) statement directly inside an expression e.g.:

function foo {
  $i = 0
  ($i++)
  $i
}

This will output @(0,1).

Bruce Payette discusses this in Chapter 5 of Windows PowerShell in Action 2nd Edition. The increment and decrement operators are "voidable statements". Quoting from the book:

Basically, this means that certain types of expressions, when used as statements, are not displayed. Voidable statements include assignment statements and the increment/decrement operators. When increment and decrement are used in an expression, they return a value, but when they’re used as a standalone statement, they return no value.

BenMorel
  • 31,815
  • 47
  • 169
  • 296
Keith Hill
  • 184,219
  • 38
  • 329
  • 358
1

That is because $l++ doesn't return anything, :

$l = 0
$l++   #nothing
$l #gives 1
$l++   #nothing
($l++)  #gives 2

This is done so that there is no confusion when you are returning to pipeline. Effectively,

$l++ is $l = $l+ 1, so it doesn't return anything.

What you want to see is $l = $l + 1; $l, which is why you have to do ($l++).

manojlds
  • 275,671
  • 58
  • 453
  • 409
0

I think there are two tasks it needs to do:

  1. Execute $l++ (increment the variable) which happens on the inner parenthesis
  2. Retrieve $l's value which happens in the outer parenthesis.

Here is a illustration of this:

$l = 0
"$($l++ ; $l)"

Outputs: 1 where

$l = 0
"$($l++)"

Doesn't output anything.

In order to receive output I need two statements inside the sub-expression. Otherwise the only thing that happens is that $l is incremented but its value is not retrieved.

Andy Arismendi
  • 48,006
  • 16
  • 103
  • 122