While working on a module that has a huge memory workload, I wanted to avoid redundant code and used the following nice tips Mike F. Robbins demonstrated in this blog post
First try the following in a console:
$test = 'Heavy task' ($test = 'Heavy task')
Do you see the difference?
Having parentheses around the variable statement also outputs the result in the console.
Isn’t it very nice?
Why there is such a difference?
Having parentheses will make the interpreter parse the simple pipeline/expression (what’s inside the parentheses) in expression mode and output the result of this expression. It’s notation is:
(<expression>)
How do I know this?
Well, I just took the example Bruce Payette gave in the “Statement termination” paragraph in his awesome book “PowerShell in Action” and the error message revealed it š
Let me also quote what’s written in the “grouping /subexpressions and array expressions” paragraph:
Parantheses group expression operations and may contain either a simple expression or a simple pipeline
The notation can be either
(<expression>)
or
(<pipeline>)
Now, consider the if/else statement for a few seconds that has the following notation:
if (<pipeline>) { <statementlist> } elseif (<pipeline>) { <statementlist> } else { <statementlist> }
It also means that you can do both the variable assignment and test if anything assigned exists inside the if pipeline/expression. It will evaluate to $true if the output exists and to $false if it doesn’t. As far as I remember, some participants in the scripting games were also using this approach and Don Jones talked about it a few years ago (if you’ve a link please share it, I’ll add it).
When you process only once the heavy workload, capture its result into the variable and immediately test if it exists, it also allows to write less code and have a slightly faster execution in memory.
Here’s an example of what I mean:
if ($test = 'do my heavy task/function/cmdlet') { $test | Do-Something } else { Do-SomethingElse }
Using the above syntax, you can actually avoid writing more code.
Please, let me repeat that there’s nothing wrong in doing the following:
# assign once but outside of the if/else statement $test = 'do my heavy task/function/cmdlet' if ($test) { $test | Do-Something } else { Do-SomethingElse }
But, you definitely should avoid running twice the heavy memory workload if you do:
if ('do my heavy task/function/cmdlet') { $test = 'do my heavy task/function/cmdlet' $test | Do-Something } else { Do-SomethingElse }
Let’s measure how fast each of these pieces of code run.
I haven’t found better examples yet but you can try these examples.
The first and second examples run almost at the same speed.
# Example1: # Both variable assignment and test # inside the if/else Measure-Command { if ($test = 1..10000 | % { $_ * 2 }) { 'ok' } else { 'nok' } } # Example2: # Variable assignment outside # and test inside the if/else Measure-Command { $test = 1..10000 | % { $_ * 2 } if ($test) { 'ok' } else { 'nok' } } # Example3: # Test an expression # Late variable assignment # Runs twice, so avoid it Measure-Command { if (1..10000 | % { $_ * 2 }) { $test = 1..10000 | % { $_ * 2 } 'ok' } else { 'nok' } }
Just a quick note…Bruce Payette’s (amazing) book is PowerShell in Action, not PowerShell in Practice.
Thanks for reporting it š I’ve fixed it by editing the post.
I’ve been using `if ($x = Get-Something) { … }` for some time, but never wondered how exactly does it work. Thanks for the explanation!