2

I have encounter some strange issue that I cannot solve so hopefully someone can shed some light in this. Not sure why, but anything I do with array from object in function, it impacts/changes also other object arrays.

Here is what I do. I describe object class:

Class testObject {
   [array] $list
   [int] $increment }

Then I create two objects that both have the same $list:

$numberList = (1,1,1,1,1,1,1,1,1)

$obj1 = New-Object testObject
$obj1.list = $numberList
$obj1.increment = 2

$obj2 = New-Object testObject
$obj2.list = $numberList
$obj2.increment = 5

Next I describe function that will increase each array item by the increment value specified in each object:

Function Increase-numbers ($obj) {
    [array] $array = $obj.list

    For ($i = 0; $i -lt 9; ++$i) {
        $array[$i] += $obj.increment }

    $obj.list = $array
    return $obj
}

Then I run the function in which I pass object to function and update the object with function results:

$obj1 = Increase-numbers $obj1
Write-Host "$($obj1.list)"

$obj2 = Increase-numbers $obj2
Write-Host "$($obj2.list)"

I would expect that returned values would be: For $obj1 (increment value = 2): 333333333 For $obj2 (increment value = 5): 666666666

But it actually returns: 333333333 888888888

This happens because in the first function call when I change the array values, it automatically updates $obj2 array values as well.

Does anyone have an idea what am I doing wrong?

mmx87
  • 23
  • 2
  • 1
    i think you are seeing the "by-reference instead of by-value" stuff. most non-simple objects are NOT passed as values ... they are passed as references. so each use of your `$numberList` array is using a **_reference_** to the array, not a copy of it. – Lee_Dailey Dec 14 '19 at 21:49
  • Thank you, you are absolutely right! Once I did "$obj2.list = $numberList.Clone()" no more reference issues! – mmx87 Dec 14 '19 at 22:11
  • you are most welcome! glad to help a bit ... [*grin*] – Lee_Dailey Dec 14 '19 at 22:16

1 Answers1

1

EDIT: as @mklement0 mentioned below, it is most likely best to do something like:

# other code here
$obj1.list = $numberList.Clone() # Instead of $numberList.PsObject.Copy()
# other code here
$obj2.list = $numberList.Clone() # Instead of $numberList.PsObject.Copy()
# other code here

This is the explanation provided:

I suggest using $numberList.Clone(), not just because it is simpler than the somewhat obscure .psobject.Copy(), but because the latter may give the mistaken impression that it is a general object-cloning mechanism, which it isn't - any instance of a reference type that isn't either [pscustomobject] or implements ICloneable will be returned as-is - in other words: the call is then effectively a quiet no-op. For instance, it works with a hashable ({ ... }), but not with the ordered variety ([ordered] @{ ... })



Original Answer:

This is happening because you are copying $numberList by reference, not by value. Once you increase the values in the first Increase-numbers it increases it for all variables that are referencing that list.

If you change:

# other code here
$obj1.list = (1,1,1,1,1,1,1,1,1)
# other code here
$obj2.list = (1,1,1,1,1,1,1,1,1)
# other code here

to this:

# other code here
$obj1.list = $numberList.PsObject.Copy()
# other code here
$obj2.list = $numberList.PsObject.Copy()
# other code here

It should work for you because you are copying the $numberList by value, to $obj1.list - copying by value treats it as a brand new variable.. You could also do something like this:

# other code here
$obj1.list = (1,1,1,1,1,1,1,1,1)
# other code here
$obj2.list = (1,1,1,1,1,1,1,1,1)
# other code here

or..

$numberList1 = (1,1,1,1,1,1,1,1,1)
$numberList2 = $numberList1.PsObject.Copy()
# other code here
$obj1.list = $numberList1
# other code here
$obj2.list = $numberList2
# other code here

or..

$numberList1 = (1,1,1,1,1,1,1,1,1)
$numberList2 = (1,1,1,1,1,1,1,1,1)
# other code here
$obj1.list = $numberList1
# other code here
$obj2.list = $numberList2
# other code here
Matt Oestreich
  • 8,219
  • 3
  • 16
  • 41