[Brisbane-pm] Passing references into Arrays
Jacinta Richardson
jarich at perltraining.com.au
Fri Feb 23 21:21:13 PST 2007
Martin Jacobs wrote:
> Perl Best Practices says 'Use a hash of named arguments for any
> subroutine that has more than three parameters'. OK, that's PERRMOSS. I
> have varied the advice, though, in that I have set up a hash of
> references to the variables (because some of the arrays will be very
> big).
I think you're making this too hard. You should be able to do the following:
do_something_cool( count => 2,
list => \@some_list,
defaults => \%defaults,
otherthing => 10,
somestring => 'dfasdfasdfsdf',
scalar => $something,
);
sub do_something_cool {
my %args = @_;
my $count = $args{count} || 0;
my $list = $args{list}; # just using the scalar avoids copying
my $hash = $args{defaults};
....
foreach my $value (@$list) {
...
}
}
You do not need to create a hash of references per se. What I have done above
will still ensure that only scalars will be passed around. Unless your simple
scalars contain very large strings in them, or you _really_ need to change their
contents, I'd suggest that you don't pass them as references, but instead pass
them by value.
> If the keys are to make sense,
> then they should have long names, like the names of the values, but then
> there's the danger of mixing up the key with the value.
Use good layout and => to help reduce this confusion. Glancing at my code above
you should be able to tell instantly which are keys and which are values.
> Version 1 works well, but the syntax is cluttered because each operation
> has to derefence each variable at every step.
It's worse than cluttered, it hurts my eyes!
> Version 2 attempts to get round this by dereferencing everything at the
> start of the sub. Does this mean it copies the variables in the sub?
Yes these dereferences are doing copying. Ideally you pass references and then
use the references - dereferencing only where you need to: as in my foreach loop
above.
> Oddly, and I don't know why, if you hash out line 31, the sub applies
> the operation to the referent outside the sub, @k
You code does this:
my @k = @{$arg_ref->{arg3}};
$k[0][0] = "$k[1][1]"."$k[1][2]";
@{$arg_ref->{arg3}} = @k;
Let's look at what this does. On the first time we dereference $arg_ref->{arg3}
to get an array. If we previously had had:
$arg_ref->{arg3} = ['a' .. 'e'];
then we would now have:
@k = ('a'..'e');
However, we previously had:
$arg_ref->{arg3} = [ref1, ref2, ref3...]
so we now have:
@k = (ref1, ref2, ref3, ...]
The second line then changes the data structure pointed at by that first
reference. So instead of saying:
$k[0] = x
which would have changed only @k, what we are instead doing is the same as:
ref1->[0] = x
So we're changing the data structure pointed to from @k[0]
Thus whether or not we re-assign @k to @{$arg_ref->{arg3}} the under-lying data
structure has been changed. The third line just involves a little more copying.
If you want true copying so that you can change parts of a data structure
without repercussions, look at Storable's "clone" method.
I hope that helps.
Now.... some comments on your included code:
> #!/usr/local/bin/perl
> use warnings;
> use strict;
> use Time::Local;
>
> #The following is provided as a 'template' for the conventions used in PERRMOSS.
> #It is based on Perl Best Practices by Damian Conway, in particular Chapter 9.
> #Chapter 9 can be found at www.oreilly.com/catalog/perlbp/chapter/ch09.pdf.
>
> &Some_block_of_code;
Subroutines really are best called with parens and no &.
Some_block_of_code();
> sub Some_sub {
...
> #Then, do some operations
> $$i = $$i + 100;
> print 'Testprint line 22 $$i = '."$$i\n";
I know this works, but that's not necessarily a good reason for doing it.
> $$j[0] = $$j[1]*$$j[2];
Much better written as:
$j->[0] = $j->[1] * $j->[2];
> my $arguments = Some_sub ({
> arg1 => \$i,
> arg2 => \@j,
> arg3 => \@k,
> arg4 => \%l,
> });
There are two good reasons for passing references to a subroutine:
1. The data structures are large and thus you don't want to copy them
2. The subroutine needs to be able to edit those data structures.
If you have a variable that doesn't fall into either of the above, don't pass
that variable as a reference. It is a very good idea to make sure that any
subroutine which changes its arguments has a name that reflects that. You don't
want to call a subroutine called:
print_data
only to find that it completely corrupts the data structures sent to it.
I've attached a slightly modified version of your code to show another
alternative. In it I return the change to $i (because I don't like references
to scalars), but if you really need to use the reference to scalar then of
course you should.
J
--
("`-''-/").___..--''"`-._ | Jacinta Richardson |
`6_ 6 ) `-. ( ).`-.__.`) | Perl Training Australia |
(_Y_.)' ._ ) `._ `. ``-..-' | +61 3 9354 6001 |
_..`--'_..-_/ /--'_.' ,' | contact at perltraining.com.au |
(il),-'' (li),' ((!.-' | www.perltraining.com.au |
-------------- next part --------------
A non-text attachment was scrubbed...
Name: test1.pl
Type: text/x-perl
Size: 2611 bytes
Desc: not available
Url : http://mail.pm.org/pipermail/brisbane-pm/attachments/20070224/02ebed98/attachment-0001.bin
More information about the Brisbane-pm
mailing list