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

I'm trying to learn a bit about passing references to subroutines. For example, with arrays I've seen the following in the subroutine that the array is being passed to:
my $myarray = shift; my $myarray = @_;
What's the difference between the two? TIA...Kevin

Replies are listed 'Best First'.
(jeffa) Re: reference question
by jeffa (Bishop) on Aug 14, 2001 at 19:38 UTC
    Looks to me like the second example is wrong. First, understand that the first example really is a shortcut for
    my $myarray = shift @_;
    Once you see that, it makes sense that $myarray contains the first element in @_ (which is the first argument passed to the subroutine).

    So, the second example would assign a '1' to $myarray, because when you assign an array to a scalar, you get the number of the elements of the array.

    Here is a test script for you to play with:

    use strict; use Data::Dumper; sub foo { my $ref = shift; print Dumper $ref; } sub bar { my $ref = @_; print Dumper $ref; } my @ary = qw(a b c d e f); my $ref = [ qw(a b c d e f) ]; foo(@ary); foo($ref); bar(@ary); bar($ref);

    ----------------------------------------------------
     perl -le '$x="jeff";$x++ for(0..4482550);print $x'
    ----------------------------------------------------
    
Re: reference question
by arturo (Vicar) on Aug 14, 2001 at 19:40 UTC

    First, you need to know that neither of these has anything *directly* to do with references. I recommend the documentation on shift to you; one thing to keep in mind here is that, inside a subroutine, the *default argument* to shift is @_ (outside, it's @ARGV which holds the arguments passed to the script), so that shift is really shift @_.

    The first line you give returns the first member of @_, making @_ one element shorter (as per the documentation for shift); the second will set $myarray to the *number* of entries in the @_ array (because you're evaluating it in a scalar context).

    The first is appropriate if you want to get a single argument from @_. The second is useful if you know you need a certain number of arguments, and want to print an error message if there aren't enough. An importantly different syntax is my ($myarray) = @_; (note parens), which evaluates @_ in *list context* and will return the first element of @_ (without removing it from @_, like shift does).

    (if you got the impression that this context business is rather important stuff, you got the right impression =)

    HTH!

    perl -e 'print "How sweet does a rose smell? "; chomp ($n = <STDIN>); +$rose = "smells sweet to degree $n"; *other_name = *rose; print "$oth +er_name\n"'
Re: reference question
by petdance (Parson) on Aug 14, 2001 at 19:40 UTC
    It's all a matter of what's being passed in, and how the function accepts it. You can pass anything you want into a function, so you need to be sure that you're passing what the function wants.

    Here's two samples:

    my @files = qw( foo bar bat ); @files = byvalue( @files ); byreference( \@files ); sub add_txt_by_value { my @array = @_; foreach ( @array ) { $_ .= ".txt"; } return @array; } sub add_txt_by_reference { my $arrayref = shift; foreach ( @$arrayref ) { $_ .= ".txt"; } }
    Note that when we pass by value, we have to pass back the array as a return value. When we pass by ref, we're modifying the array in the caller's space.

    Updated: s/$array/$arrayref/ in the second example. Thanks, Hofmator.

    xoxo,
    Andy
    --
    <megaphone> Throw down the gun and tiara and come out of the float! </megaphone>

      and as a third alternative - change the passed arguments directly:

      sub add_txt_directly { foreach ( @_ ) { $_ .= '.txt'; } }

      -- Hofmator

Re: reference question
by Hofmator (Curate) on Aug 14, 2001 at 19:51 UTC

    Assuming both of them are called at the top of a subroutine ... my $myarray = shift; puts the first argument to the subroutine into the variable $myarray - no matter what the first argument is, it could be an array reference but it does not have to be. my $myarray = @_; This puts the number of arguments the subroutine was called with into $myarray - evaluating an array in scalar context.

    To demonstrate passing an arrayref into a subroutine look at this:
    sub print_arr { my $count = @_; my $arrayref = shift; print "I have been called with $count arguments.\n"; print "$_!!\n" for (@$arrayref) } my @arr = qw/Beer Wine PerlMonks/; print_arr(\@arr);
    If you call it like this print_arr(@arr) then the $arr[0] will be put into $arrayref and an error occurs when perl tries to do @$arrayref because 'Beer' is not a valid reference. (Note that the function now is called with 3 arguments, @arr is flattened out!)

    -- Hofmator

Re: reference question
by John M. Dlugosz (Monsignor) on Aug 15, 2001 at 02:30 UTC
    I think you meant my ($myarray) = @_; in the second line.

    Two common styles of paramater setting-up are shifts and assignment of @_. Sometimes they are mixed. Shift is a simple way to grab one argument. Assignment does them all. Shifting modifies the argument list, assignment doesn't.

    For one parameter, it means the same thing, if you won't be using @_ anymore (so you don't care that you changed it).

    Look at this:

    my $this= shift; # ... do some checking here. my ($x,$y,$z)= @_;