Powershell: Add-Member affects variables passed by value to a function

Created on 22 Nov 2019  路  4Comments  路  Source: PowerShell/PowerShell

Steps to reproduce

PS > function test($val){
>> $val | Add-Member -NotePropertyMembers @{Test=10}
>> }
PS > $num = 5
PS > test($num)
PS > $num.Test
10
PS > $num | Get-Member -View Extended

   TypeName: System.Int32
Name MemberType   Definition
---- ----------   ----------
Test NoteProperty int Test=10

Expected behavior

Function arguments of value types are passed by their values and any modifications to them,
including extension of thier members by Add-Member cmdlet, should not be seen by a caller.

Actual behavior

A NoteProperty was added to the [int] variable inside the function while passing it by value.

Environment data

PSVersion                      6.2.3
PSEdition                      Core
GitCommitId                    6.2.3
OS                             Microsoft Windows 10.0.18362
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0鈥
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0
Issue-Question Resolution-Answered

Most helpful comment

The main thing here is that the parameter $val is typed as object. The value stored in $num is first boxed when it's saved as a variable. Variables in PowerShell are implemented as PSVariable objects (for the most part) where the value is stored on a property public object Value { get; }. Since the parameter is also typed as object, the boxed value is passed to the function. If you change the parameter type to int it doesn't repro anymore.

All 4 comments

All values in PowerShell are "boxed" by design.

小oming from its nature PowerShell cannot handle values like C# - all values are boxed by design and passed by reference. This leads to performance (memory allocations) issues. Implementing argument passing by value in scripts will only worsen this problem (We have some issues for this.). Conversely, PowerShell uses caching to reduce memory allocations.

Really that we can do here - address a specific business scenario if we get it or a hot code path. But again, it will most likely be a movement in the opposite direction from what you request. (We already had such perf PRs.)

/cc @daxian-dbw @SeeminglyScience @mklement0 if they want to add more.

The main thing here is that the parameter $val is typed as object. The value stored in $num is first boxed when it's saved as a variable. Variables in PowerShell are implemented as PSVariable objects (for the most part) where the value is stored on a property public object Value { get; }. Since the parameter is also typed as object, the boxed value is passed to the function. If you change the parameter type to int it doesn't repro anymore.

@iSazonov @SeeminglyScience thanks, clear explantaion

Was this page helpful?
0 / 5 - 0 ratings