3

I use @_ in a subroutine to get a parameter which is assigned as a reference of an array, but the result dose not showing as an array reference.

My code is down below.

my @aar = (9,8,7,6,5);

my $ref = \@aar;

AAR($ref);

sub AAR {
   my $ref = @_;
   print "ref = $ref";
}

This will print 1 , not an array reference , but if I replace @_ with shift , the print result will be a reference.

can anyone explain why I can't get a reference using @_ to me ?

zdim
  • 64,580
  • 5
  • 52
  • 81
Henry Lu
  • 45
  • 6

2 Answers2

8

This is about context in Perl. It is a crucial aspect of the language.

An expression like

my $var = @ary;

attempts to assign an array to a scalar.

That doesn't make sense as it stands and what happens is that the right-hand side is evaluated to the number of elements of the array and that is assigned to $var.

In order to change that behavior you need to provide the "list context" to the assignment operator. In this case you'd do

my ($var) = @ary;

and now we have an assignment of a list (of array elements) to a list (of variables, here only $var), where they are assigned one for one. So here the first element of @ary is assigned to $var. Please note that this statement plays loose with the elusive notion of the "list."

So in your case you want

my ($ref) = @_;

and the first element from @_ is assigned to $ref, as needed.

Alternatively, you can remove and return the first element of @_ using shift, in which case the scalar-context assignment is fine

my $ref = shift @_;

In this case you can also do

my $ref = shift;

since shift by default works on @_.

This is useful when you want to remove the first element of input as it's being assigned so that the remaining @_ is well suited for further processing. It is often done in object-oriented code.


It is well worth pointing out that many operators and builtin facilities in Perl act differently depending on what context they are invoked in.

For some specifics, just a few examples: the regex match operator returns true/false (1/empty string) in scalar context but the actual matches in list context, readdir returns a single entry in scalar context but all of them in list context, while localtime shows a bit more distinct difference. This context-sensitive behavior is in every corner of Perl.

User level subroutines can be made to behave that way via wantarray.


See Scalar vs List Assignment Operator for a detailed discussion

See it in perlretut and in perlop for instance

zdim
  • 64,580
  • 5
  • 52
  • 81
  • 2
    Thank you for your explanation. Your answer makes me know the perl syntax better. – Henry Lu Nov 02 '18 at 04:06
  • @HenryLu You are welcome. I suggest that you read through `perldata` (first link) and then look around [perldoc](https://perldoc.perl.org/perldoc.html) for other resources. Also see [learn.perl.org](https://learn.perl.org/) – zdim Nov 02 '18 at 05:25
  • An addendum that may be helpful to know in the long run: it is not () that creates lists, as `1, 2, 3` and `1..5` and `@foo` are all lists as long as they're in list context (for example, the arguments to a subroutine, or the list a foreach iterates over). This is just a special case: parentheses around the left side of an assignment turns it into a list assignment. And you often need parentheses around lists on the right side of an assignment just for precedence. More: http://altreus.blogspot.com/2011/08/lists-and-things-made-of-lists.html – Grinnz Nov 02 '18 at 05:27
  • @Grinnz That should be helpful for the OP, and then I'd add that a "list" is an elusive notion to start with (but I didn't mean to go there for this). Also, as the LHS `()` imposes the list context on the `=` op the RHS list is copied into the LHS _list_ (um, variables in "the list"). So we do "get a list" by `()` -- very loosely (and imprecisely) speaking. Again, it is correct that a "list" can't be created by syntax (it's on the stack, and the term is related to how operators work in the given context) but this is getting into slippy semantics :) – zdim Nov 02 '18 at 05:50
2

When you assign an array to a scalar, you're getting the size of the array. You pass one argument (a reference to an array) to AAR, that's why you get 1.

To get the actual parameters, place the local variable in braces:

sub AAR {
   my ($ref) = @_;
   print "ref = $ref\n";
}

This prints something like ref = ARRAY(0x5566c89a4710).

You can then use the reference to access the array elements like this:

print join(", ", @{$ref});
Robert
  • 7,394
  • 40
  • 45
  • 64