Original Question Below. See Edit #2.
I'm new to powershell and am trying to figure out how to use return values from functions. I have a background in C++ so when I say "by reference", "by value", I mean it in the C++ sense.
I've read MSDN: about_return and this statement sounds straight forward:
In PowerShell, the results of each statement are returned as output, even without a statement that contains the Return keyword. Languages like C or C# return only the value or values that are specified by the return keyword.
But I don't think I understand its implications. I wrote the function below to explain what I would like my powershell function to do. Apparently, powershell has very non-intuitive return semantics.
MultBy
should take $i
by value, multiply it with $multiplier
and return the product. MultBy
should also take $j
by reference, and in the same invocation, multiply $j
by 200
and the product should be visible in the scope of Main()
. I also want to suppress the output 3000
when calling return
.
function MultBy
{
param
(
[Parameter(Mandatory, Position=0)]$i,
[Parameter(Mandatory, Position=1)]$j,
[Parameter(Mandatory, Position=2)]$multiplier,
[Parameter(Mandatory, Position=3)][string]$operation
)
Write-Output "Performing ""${operation}"":"
$i *= $multiplier
$j *= 200
Write-Output "Inside MultBy: `$i: ${i}, `$j: ${j}"
return $i
}
function Main()
{
$n = 30
$m = 40
$mult = 100
$operation = "Operation #1"
# Q1. How to pass $m by reference and have MultBy modify it?
MultBy $n $m $mult $operation
Write-Output "After first call: `$n: ${n}, `$m: ${m}" # (1)
# Q2. How to use the return value of MultBy to reassign to $n?
$n = MultBy $n $m $mult $operation # (2)
Write-Output "After second call `$n: ${n}, `$m: ${m}"
}
# Start this script
Main
Output
Performing "Operation #1":
Inside MultBy: $i: 3000, $j: 8000
3000
After first call: $n: 30, $m: 40
After second call $n: Performing "Operation #1": Inside MultBy: $i: 3000, $j: 8000 3000, $m: 40
Result from Line (1)
indicates that arguments are passed by value. And the execution order around line (2)
just doesn't make sense: it looks like Write-Output in the subsequent line was called before the second call to MultBy
.
Some SO questions I've looked at but didn't help:
SO-1: How to return one and only one value from a PowerShell function?
SO-2: How to use a powershell function to return the expected value?
SO-2 suggests using classes, whose return semantics within class methods are more consistent with other language's usages.
EDIT #1
Per this and this discussion, the output behaves more predictably when I changed Write-Output
to Write-Host
.
function MultBy
{
param
(
[Parameter(Mandatory, Position=0)]$i,
[Parameter(Mandatory, Position=1)]$j,
[Parameter(Mandatory, Position=2)]$multiplier,
[Parameter(Mandatory, Position=3)][string]$operation
)
Write-Host "Performing ""${operation}"":"
$i *= $multiplier
$j *= 200
Write-Host "Inside MultBy: `$i: ${i}, `$j: ${j}"
return $i
}
function Main()
{
$n = 30
$m = 40
$mult = 100
$operation = "Operation #1"
# Q1. How to pass $m by reference and have MultBy modify it?
MultBy $n $m $mult $operation | Out-Null
Write-Host "After first call: `$n: ${n}, `$m: ${m}"
# Q2. (Solved)
$n = MultBy $n $m $mult $operation
Write-Host "After second call `$n: ${n}, `$m: ${m}"
}
# Start this script
Main
Output
Performing "Operation #1":
Inside MultBy: $i: 3000, $j: 8000
After first call: $n: 30, $m: 40
Performing "Operation #1":
Inside MultBy: $i: 3000, $j: 8000
After second call $n: 3000, $m: 40
EDIT #2
Adding [ref] to $j declaration results in an error:
function MultBy
{
param
(
[Parameter(Mandatory, Position=0)]$i,
[Parameter(Mandatory, Position=1)][ref]$j,
[Parameter(Mandatory, Position=2)]$multiplier,
[Parameter(Mandatory, Position=3)][string]$operation
)
Write-Host "Performing ""${operation}"":"
$i *= $multiplier
$j *= 200
Write-Host "Inside MultBy: `$i: ${i}, `$j: ${j}"
return $i
}
function Main()
{
$n = 30
[ref]$m = 40
$mult = 100
$operation = "Operation #1"
# Q1. How to pass $m by reference and have MultBy modify it?
MultBy $n $m $mult $operation | Out-Null
Write-Host "After first call: `$n: ${n}, `$m: ${m}"
# Q2. (Solved)
$n = MultBy $n $m $mult $operation
Write-Host "After second call `$n: ${n}, `$m: ${m}"
}
# Start this script
Main
Error Output
Method invocation failed because [System.Management.Automation.PSReference`1[[System.Int32, mscorlib, Version=4.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089]]] does not contain a method named 'op_Multiply'.
At D:\...\Code\Powershell\ex_Functions\ex_Functions.ps1:13 char:4
+ $j *= 200
+ ~~~~~~~~~
+ CategoryInfo : InvalidOperation: (op_Multiply:String) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound