0

My understanding from PERLVARS is that the '@_' variable is the list of parameters supplied to a subroutine. My understanding is that the 'shift' function pops the first value from that list, but that the elements of @_ can also be accessed directly, as with any other list. The problem I am seeing is that when a subroutine is called more than once, the @_ list always contains the values from the very first call, and the values don't seem to be updated.

#!/usr/bin/perl

#Test the shift command
foreach(1..5) {
    print "Input: $_    ";
    &Test_Shift($_);
}

#Test the @_ list
foreach(1..5) {
    print "Input: $_    ";
    &Test_List($_);
}


sub Test_Shift() {
    my $Test1 = shift;
    print "Returns: $Test1 \n";
}


sub Test_List() {
    my $Test2 = @_;
    print "Returns: $Test2 \n"; 
}

Results

Input: 1    Returns: 1 
Input: 2    Returns: 2 
Input: 3    Returns: 3 
Input: 4    Returns: 4 
Input: 5    Returns: 5 
Input: 1    Returns: 1 
Input: 2    Returns: 1 
Input: 3    Returns: 1 
Input: 4    Returns: 1 
Input: 5    Returns: 1 

What am I doing wrong or misunderstanding?

UPDATE

As recommended by Ikegami, I changed the following line

#Original
my $Test2 = @_;

#New
my ($Test2) = @_;

This results in the expected output. As Ikegami has reminded me, when a list is coerced into a scalar context, the value becomes the size of the list.

Byron Jones
  • 315
  • 2
  • 11
  • 1
    A good resource: http://perldoc.perl.org/perlsub.html – squiguy Feb 26 '16 at 22:42
  • 2
    By the way, your prototypes (`()`) are incorrect (they indicate the subs accept no arguments), which is why you had to override them by using `&`. Get rid of both the prototypes and `&`. – ikegami Feb 26 '16 at 22:42
  • 2
    You'll see the problem better if you change `1..5` to `4..9` – ikegami Feb 26 '16 at 22:43
  • 1
    Re "*when a list is coerced into a scalar context, the value becomes the size of the list.*", That's not true. Context doesn't coerce values, it affects what the operator returns in the first place. `@_` doesn't return a list that is coerced; `@_` returns the number of elements it contains. – ikegami Feb 26 '16 at 22:52
  • I had read something that said that only newer versions of Perl fully supported subroutine parameters, and that prototypes in Perl didn't work the way some expected them to. Unfortunately I'm still figuring out Perl best practice vs what is allowed for the older version of Perl I am required to use. – Byron Jones Feb 26 '16 at 22:53
  • My comment about prototypes pertains to all existing version of Perl 5. – ikegami Feb 26 '16 at 22:53
  • I guess I'm still confused. My understanding is that @_ is a list object, and that as such, it has one or more scalar values, represented by an index, as well as a count of those scalars (and the count itself is a scalar). When the list is coerced into scalar context, Perl automatically returns the count,, whereas $(@_[0]) would return the first scalar value. Am I still not getting Perl? :) – Byron Jones Feb 26 '16 at 22:57
  • Actually, I think it was the PERLSUB page discussion of PROTO vs signatures that had left me more confused than when I started. From what I could gather on that page, more recent versions of Perl have been transitioning to a subroutine pattern that more closely resembles other languages, where the parameter signature is fully preserved, rather than having all parameters joined into a list. – Byron Jones Feb 26 '16 at 23:05
  • 2
    @ByronJones: It seems to be your efforts to interpret Perl code in C++ terms that is tripping you up. `@_` is not a *list object*, it is an *array*. When an array is used in *scalar context* it evaluates to the number of elements in the array. (When it is used in *list context* it evaluates to a list of the values of its elements.) The first element of any array `@xx` is a *scalar* value and so has a dollar prefix `$xx[0]`. `$(@_[0]) ` isn't anything special and is a syntax error. You should be ignoring prototypes for now. Their purpose is far more esoteric in Perl than in other languages. – Borodin Feb 26 '16 at 23:42
  • @ByronJones: Likewise, subroutine signatures are an *experimental* facility and you should also ignore those. I'm unclear what you may mean by *"where the parameter signature is fully preserved, rather than having all parameters joined into a list"*. If you remember that Perl scalars are multi-typed, and may have a string value and an integer value (or a string value and a float value) simultaneously, then it may help you to understand why no more than an array of values is necessary, except perhaps to pass named parameters out of order or to omit optional parameters – Borodin Feb 26 '16 at 23:49
  • [Arrays are not lists](http://friedo.com/blog/2013/07/arrays-vs-lists-in-perl). – Dave Cross Feb 27 '16 at 13:41

1 Answers1

4
my $Test2 = @_;

evaluates @_ in scalar context, which evalutes to the number of elements in the array. You want

my ($Test2) = @_;
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • Yes, you're absolutely right. Coming from a more C/C++/C# history, the Perl way of handling variables is something that is tripping me up far more than I would like. – Byron Jones Feb 26 '16 at 22:45
  • Why bother answering a question that's so obviously a duplicate? – Matt Jacob Feb 27 '16 at 00:02
  • 1
    @Matt Jacob, Because so-called duplicates rarely are. Best to answer *and* to close. – ikegami Feb 27 '16 at 00:09
  • In defense, I _did_ search for other questions involving @_. I did not find the previous question. I assume that '@_' versus "@_" was tripping up the search algorithm. – Byron Jones Feb 29 '16 at 15:19