Re: Pass by Value does not work
by almut (Canon) on Feb 21, 2009 at 09:42 UTC
|
You haven't made a 'deep' copy of your data structure, which means the array references are still pointing to the original data. You've only copied the references themselves...
| [reply] |
|
|
| [reply] |
|
|
Not to sound too dense, but doesn't Perl always use "pass by reference," in that changing anything in the $@ array will change its values in the calling routine?
Of course, the language I grew up using always passes by reference, so it usually takes a mental effort to assume any changes in a sub to passed variables don't propagate upstream.
Information about American English usage here and here. Floating point issues? Please read this before posting. — emc
| [reply] |
|
|
I suppose the OP was thinking that - due to the @ali = @_ - the
entire data structure would be copied... And the "pass by value" was probably referring to left_triangle(@xx) vs. left_triangle(\@xx) — with the "values" being the array refs. (Only the OP can tell
for sure, though, what his/her expectation had been.)
| [reply] [d/l] [select] |
|
|
Re: Pass by Value does not work
by duelafn (Parson) on Feb 21, 2009 at 13:33 UTC
|
While merlyn's article does cover the issue, the short answer/easy solution is to use Storable's dclone (core module since 5.8.0)
#!/usr/bin/perl
use warnings;
use strict;
use diagnostics;
use Storable qw/dclone/;
use Data::Dumper;
sub left_triangle {
my @ali=map dclone($_), @_;
my @aoa2;
foreach (1..@ali-1) {
pop @{$ali[$_]};
#push @aoa2, $ali[$_];
}
return \@ali;
}
my @xx = ([3],[7,5],[2,4,6],[8,5,9,3]);
print Dumper left_triangle(@xx);
print Dumper \@xx;
| [reply] [d/l] |
Re: Pass by Value does not work
by velusamy (Monk) on Feb 21, 2009 at 09:53 UTC
|
Hi,
The @xx was having elements as array references. In subroutine you changed @xx values but the values were references so that only your array values were affected. | [reply] |
|
|
Thanks all, I now understand it.
| [reply] |
Re: Pass by Value does not work
by Marshall (Canon) on Feb 22, 2009 at 23:00 UTC
|
When you call left_triangle with what we call a List of List (LoL), you are passing a list of references to the sub, the reference to list(s) (3), (7,5), (2,4,6), (8,5,9,3). In Perl [] means reference to or address of or pointer to, basically the same idea. my @xx = ([3],[7,5],[2,4,6],[8,5,9,3]); is a list of 4 references to other lists. If you use that pointer to the list, then you are modifying the list itself.
Perl is MAGIC with lists!
How do you clone a LoL (List of List)? This is also called a "deep copy".
Easy:
my @xx_clone = map {[$_]}@xx;
Correction: my @xx_clone = map {[@$_]}@xx;
map is a transformation operator that operates on lists.
Here a list of references to lists (@xx) goes into the map. Then each list gets expanded via @$_, then enclosed within a new address (the [] operator) and a new list of those is passed to @xx_clone. So we have a new List of Lists! One line!
To do this in other languages like C, requires a lot of code! And if we are talking about "ragged arrays" like we have here with varying numbers of columns, even more code!
| [reply] [d/l] [select] |
|
|
my @xx_clone = map { [ @{$_} ] } @xx;
| [reply] [d/l] |
|
|
I think we were both a little wrong..ooops..
my @xx_clone = map { [ @$_ ] } @xx;
looks like that's better.. Thanks!!!..
UpdateI corrected post above. Thanks again. In general the {} are only needed when subscripts are involved. Another situation is say: @list = @{listref_returning_fun()}; In above posts, to get array back, my @lol = @{left_triangle(@xx)};
The above posts return reference to lists of lists. to get the LOL back, deference one time using @X= @{subroutine()} syntax.
| [reply] [d/l] |
|
|