pkperl has asked for the wisdom of the Perl Monks concerning the following question:

How to use @EXPORT in perl with example.

Replies are listed 'Best First'.
Re: Array or Hash Reference to Subroutine
by AR (Friar) on Apr 29, 2010 at 19:28 UTC

    If I understand you correctly, you are asking why would someone pass an array or hash reference to a subroutine.

    There are two reasons I can think of immediately: passing multiple distinct arrays/hashes to a subroutine and passing an array or hash that you want to manipulate in the subroutine.

    If you pass multiple arrays into a subroutine, there's no way to distinguish where one ends and the next begins. That's why you would pass them as references.

    If your subroutine adds or removes elements from the hash or array and you want that to be reflected when the subroutine ends, you must pass by reference.

    Edit: Here's some code to show what I mean.

    #!/usr/bin/perl use warnings; use strict; my @a = qw( a1 a2 a3 ); my @b = qw( b1 b2 b3 ); my %c = ( a=>1, b=>2 ); my %d = ( c=>3, d=>4 ); sub multi_flat { # my ( @foo1, @foo2 ) = what should go here? # my ( @foo1, @foo2 ) = ( shift, shift ) ? # my ( @foo1, @foo2 ) = ( $_[0], $_[1] ) ? my @foo = @_; #this flattens the arrays into one print join( ", ", @foo), "\n"; } multi_flat( @a, @b ); #prints "a1, a2, a3, b1, b2, b3" multi_flat( %c, %d ); #prints "a, 1, b, 2, c, 3, d, 4" sub multi_fixed_arr { my ( $arr1, $arr2 ) = @_; print "\$arr1 is ", join( ", ", @$arr1), "\n"; print "\$arr2 is ", join( ", ", @$arr2), "\n"; } sub multi_fixed_hash { my ( $hash1, $hash2 ) = @_; print "keys \$hash1 is ", join( ", ", keys %$hash1), "\n"; print "keys \$hash2 is ", join( ", ", keys %$hash2), "\n"; } multi_fixed_arr( \@a, \@b ); #prints: $foo1 is a1, a2, a3 # $foo2 is b1, b2, b3 multi_fixed_hash( \%c, \%d ); #prints: keys $foo1 is a, b # keys $foo2 is c, d sub pop_one { my @arr1 = @_; pop @arr1; } print join( ", ", @a), "\n"; #prints "a1, a2, a3" pop_one( @a ); print join( ", ", @a), "\n"; #prints "a1, a2, a3" sub pop_one_fixed { my $arr = shift; pop @$arr; } print join( ", ", @a), "\n"; #prints "a1, a2, a3" pop_one_fixed( \@a ); print join( ", ", @a), "\n"; #prints "a1, a2"
Re: Array or Hash Reference to Subroutine
by toolic (Bishop) on Apr 29, 2010 at 19:42 UTC
Re: Array or Hash Reference to Subroutine
by ikegami (Patriarch) on Apr 29, 2010 at 20:23 UTC
    As opposed to what? arrays and hashes? You can't pass those to subroutines. You can only pass a list of scalars to a subroutine. If you have an array or a hash in your parameter list, it gets flattened into a list of its elements. Sometimes, one can recreate the array or hash from that list. But while the whole concept of flattening an array or a hash then creating a new array or hash is pretty icky, the real problem is that often one cannot recreate the original variables.
    sub f { my (@a,%h) = @_; print("The array has ", 0+@a, " elements\n"); print("The hash has ", 0+keys(%h), " elements\n"); } my @a = qw( a b c ); my %h = ( d=>4, e=>5, f=>6 ); f(@a,%h); # Same as f($a[0],$a[1],$a[2],'e',$h{e},'d',$h{d},'f',$h{f})
    The array has 9 elements The hash has 0 elements

    Since one often has to use references, it's not a bad idea to default to passing a reference. At least, that's the reason I do it. It gets confusing if you're not consistent.

Re: Array or Hash Reference to Subroutine
by talexb (Chancellor) on Apr 29, 2010 at 20:48 UTC

    Pass by reference is preferred over pass by value when making a call to a subroutine, because at the lowest level it means a data pointer is passed on the call stack, rather than a copy of the contents of that data pointer.

    This makes a difference because it takes time and space to copy data from a local location to a stack before the call, and more time and space to copy data from the stack to another local location. You can save time and space at both ends by just using a pointer, at the slight cost of additional complexity.

    The complexity is well-hidden in Perl (and other high level languages); we just add a single character to indicate the indirection in the subroutine call, and understand that we'll be dealing with a reference in the subroutine.

    Once you are more experienced in writing code, this will come very easily to you.

    Alex / talexb / Toronto

    "Groklaw is the open-source mentality applied to legal research" ~ Linus Torvalds

      You seem to be confusing passing by reference with passing a reference. Perl always passes by reference, whether what you are passing is a reference or not.

      On the other hand, a sub that starts with my (...) = @_; or similar effectively causes Perl to pass by value, even when you pass a reference.

      The difference is not between passing by reference and passing by value. The difference in the size of the list being passed. When passing a reference to an array to a sub, only one argument is placed on the stack. When passing an array's contents to a sub, as many arguments are placed on the stack as there are elements in the array.

      Seeing as the latter is done using a simple memcpy, performance should not be an issue. And it isn't. Using the reference is actually 9% slower for a typical array (N=10)!

      Rate list ref list_nc list 132332/s -- -52% -56% ref 273067/s 106% -- -9% list_nc 300755/s 127% 10% --

      Even for very large arrays, the performance of just passing the array's elements is quite good. Passing all 10,000 elements of an array is only 14% slower than passing the reference alone!

      Rate list list_nc ref list 148/s -- -69% -73% list_nc 469/s 218% -- -14% ref 545/s 269% 16% --

      Performance gains is obviously not the reason passing references is done. (Although perceived performance gains could be.)

      (I included a trivial load to get more reasonable numbers.)

      Benchmark code: