Krab
Krab

Reputation: 6756

Perl - passing argument to push function by value

push (@{$processor{$-[0]}}, $metadata[$_]{"formatters"});
foreach my $key (keys @{$metadata[$_]{"formatters"}}) {
    $metadata[$_]{"formatters"}[$key]{"scope"} = "end";
}
push (@{$processor{$+[0]}}, $metadata[$_]{"formatters"});

I push $metadata[$_]{"formatters"} into @{$processor{$-[0]}}. Then i need change something and push it again, but these changes are reflected too where i push first. Seems like i am passing this $metadata[$_]{"formatters"} by reference and not by value, but i can`t find, how to pass it by value.

Upvotes: 1

Views: 184

Answers (3)

Borodin
Borodin

Reputation: 126722

I am very worried about your design. A structure like

$metadata[$_]{formatters}[$key]{scope}

is complex, and it seems you have multiple copies of very similar data.

However, the problem is that $metadata[$_]{formatters} is a reference to an array of hashes. Wherever you put that reference it will refer to the same data, so modifying it will be reflected in any reference to it.

You need to copy your array of hashes to an identical data structure before modifying it, and you can do that using this code. I have a suspicion that the array is a sparse one (i.e. that not all of its elements contain data) and have coded accordingly. If I am wrong, and every element is a hash reference, then you can simplify this to my $copy = [ map { {%$_} } @$formatters ].

my $formatters = $metadata[$_]{formatters};

{
  my $copy = [ map $_ ? {%$_} : undef, @$formatters ];
  push @{$processor{$-[0]}}, $copy;

  for my $key (0 .. $#$copy) {
    $copy->[$key]{scope} = 'end';
  }
}

{
  my $copy = [ map $_ ? {%$_} : undef, @$formatters ];
  push @{$processor{$+[0]}}, $copy;
}

Upvotes: 1

Steve Madere
Steve Madere

Reputation: 509

This code won't even compile. You are calling keys on @{$metadata[$_]{"formatters"}} which is not a hash, it's an Array.

The question is ill-formed.

This code is incredibly convoluted and hard to understand. I strongly recommend using the -> notation when nesting structures like this to make it clear that you are using references to substructures.

To deep-copy a structure so that you don't end up getting references to subcomponents, I would suggest cloning. e.g.:

use Clone qw(clone);
push (@{$processor{$-[0]}}, clone($metadata[$_]{"formatters"}));

Upvotes: -1

ysth
ysth

Reputation: 98398

Since $metadata[$_]{'formatters'} is itself a complex datastructure, it doesn't have a "value" per se. You can push a copy of it, though.

To just make a shallow copy (probably not what you want, since the new array will still have references to all the same hashes):

$orig = $metadata[$_]{'formatters'};
$copy = [ @$orig ];

To copy each referred-to hash also:

$orig = $metadata[$_]{'formatters'};
$copy = [ map +{%$_}, @$orig ];

Or to just copy any arbitrary datastructure:

$copy = Storable::dclone($orig);

(There are various Clone modules on CPAN that also do this.)

Upvotes: 4

Related Questions