Prevent variable from breaking out of Function scope

This topic contains 3 replies, has 2 voices, and was last updated by  Ili Metuki 10 months, 2 weeks ago.

  • Author
    Posts
  • #59380

    Ili Metuki
    Participant

    Hi
    I'm now to this forum (:

    I encountered the following behavior:
    If you pass a variable to a function and change it inside it, it will not change the variable at the parent scope as expected (without overriding the scope with $global: or something like this).
    But if you do the same with complex objects the function will override the variable on the parent scope unexpectedly.

    1. Why is that happening?
    2. How to prevent it?

    Example

    $VarOut = @{'A' = 'Out'}
    'Start: ' + $VarOut['A'] #Will output 'Out'
    
    function Get-Something
    {
        [CmdletBinding()]
        param
        (
            $VarIn
        )
        $VarIn['A'] = 'In'
        'In function: ' + $VarIn['A'] #Will output 'In'
    }
    Get-Something -VarIn $VarOut
    
    'End: ' + $VarOut['A'] #Will output 'In' and not 'Out'
    

    Thank you

  • #59386

    Matt McNabb
    Participant

    I think the problem you're having is due to the type of value you're passing in to the function, which is a hashtable. This is a reference type, so when you re-assign the value of the 'A' key, then it does it by reference to the original which is saved as variable $VarOut. There's a decent explanation of the difference in reference and value types here:

    You can see the difference if you change your script to only pass string values:

    $VarOut = 'Out'
    'Start: ' + $VarOut #Will output 'Out'
    
    function Get-Something
    {
        [CmdletBinding()]
        param
        (
            $VarIn
        )
        $VarIn= 'In'
        'In function: ' + $VarIn #Will output 'In'
    }
    Get-Something -VarIn $VarOut
    
    'End: ' + $VarOut #Will output 'Out'
    
    • #59392

      Ili Metuki
      Participant

      Thank you
      "Reference types" this was the term I was looking for

  • #59388

    Ili Metuki
    Participant

    Hi

    I fund the the solution, I just needed to clone it before editing

    $VarOut = 'Out'
    'Start: ' + $VarOut #Will output 'Out'
    
    function Get-Something
    {
        [CmdletBinding()]
        param
        (
            $VarIn
        )
        $VarIn = $VarIn.Clone() #Fix
        $VarIn= 'In'
        'In function: ' + $VarIn #Will output 'In'
    }
    Get-Something -VarIn $VarOut
    
    'End: ' + $VarOut #Will output 'Out'
    

You must be logged in to reply to this topic.