5

I don't understand how this would return 4 as an answer. Not sure what is happening inside the subroutine.



sub bar {@a = qw (10 7 6 8);}
my $a = bar(); 
print $a; 

# outputs 4

airnet
  • 2,565
  • 5
  • 31
  • 35
  • 3
    I recommend reading the "Context" section in [Learn Perl in about 2 hours 30 minutes](http://qntm.org/files/perl/perl.html). – ThisSuitIsBlackNot Aug 12 '13 at 18:24
  • Context! I remember in Learning Perl that regarding this context issue there was a line saying something like "this is the most important lesson you will learn in this book, in fact, this is the most important lesson you will learn in your whole Perl career". After 4 months of painful Perl OTJ, I can assure the man was wise. – ado Aug 13 '13 at 03:40

3 Answers3

12

The subroutine is called in a scalar context. The last statement in the subroutine is the assignment to @a, which is an expression and so becomes the implied return value. In a scalar context, this evaluates to the number of elements returned by the assignment's right-hand side (which happens to be the same as the number of elements in @a).

ikegami
  • 367,544
  • 15
  • 269
  • 518
Ted Hopp
  • 232,168
  • 48
  • 399
  • 521
  • But there is no return statement. – airnet Aug 12 '13 at 18:20
  • 9
    return is implicit in perl – mpapec Aug 12 '13 at 18:20
  • @airnet - I modified my answer a bit. – Ted Hopp Aug 12 '13 at 18:20
  • 2
    @ikegami - Where did I say that last expression evaluated is `@a`? I said that the last _statement_ is the assignment to `@a` and that this (statement) is an _expression_. The value of the expression (which, as you say, is the RHS value) becomes the return value for the subroutine. The point was that this happens _because the statement is an expression_. The "array length" refers to the length of the array that is the value of the assignment expression (not the length of the LHS). – Ted Hopp Aug 12 '13 at 20:56
  • Arrays evaluate to their length in scalar context, and the only way it could be evaluated in scalar is if it was the returned value. If you want me to be more precise as to what about your post is wrong: 1) The list assignment operator does not evaluate its LHS in scalar context, 2) the array is not evaluated in scalar context. 3) The array does not evaluate to its length, and 4) the list assignment operator does not evaluate to the array length. So yes, your answer was very very wrong. (I have just fixed it.) – ikegami Aug 13 '13 at 03:36
  • Well, partially fixed. The lack of distinction between the two assignment operators is misleading. – ikegami Aug 13 '13 at 03:41
  • @ikegami - I have no quarrel with your change to my answer, but I disagree that it changed what I was saying. The original answer used "the array length", which I grant was ambiguous (which array?), but by which I intended to refer to the result of the assignment expression. (You uncharitably continue to insist that I was talking about the LHS.) The assignment expression evaluates to an array; this is the array that is evaluated in a scalar context so as to assign a value to `$a` in OP's code. – Ted Hopp Aug 13 '13 at 04:54
  • Re <> It's not ambiguous (there's only one array) and it's wrong (the number returned has nothing to do with any arrays). – ikegami Aug 13 '13 at 05:40
  • Re: "You uncharitably continue to insist that I was talking about the LHS", Are you saying the array isn't the assignment's LHS operand? – ikegami Aug 13 '13 at 05:42
  • Re: "The assignment expression evaluates to an array", No, it doesn't. It evaluates to a number, the number of elements to which its RHS evaluated. No arrays are involved, not even in list context. – ikegami Aug 13 '13 at 05:49
  • Again, please read my answer. You're spreading completely false information. – ikegami Aug 13 '13 at 05:52
  • @ikegami - You claim "there's only one array"; does that mean that the RHS of the assignment is not an array? I realize that many people have decided that the terms "array" and "list" mean completely different things in Perl. That is overly pedantic. It would mean, for instance, that [the perldata documentation](http://perldoc.perl.org/perldata.html) is wrong when it says, _"All data in Perl is a scalar, an array of scalars, or a hash of scalars."_ Or perhaps you can explain why the RHS of the assignment is not data, or, if it is, why it is a scalar or a hash of scalars (and not an array). – Ted Hopp Aug 13 '13 at 15:37
  • Re "does that mean that the RHS of the assignment is not an array?", Correct, it's a `qw` operator, and it returns a list of scalars. Compare `perl -E'@a=(4,5,6);say 0+@a;'` and `perl -E'say 0+qw(4 5 6);'` – ikegami Aug 13 '13 at 16:29
  • Re "It would mean, for instance, that the perldata documentation is wrong", No, the data returned by `qw` is stored in scalars. – ikegami Aug 13 '13 at 16:29
  • Re "Or perhaps you can explain why the RHS of the assignment is not data", It's not data. It's code, it's an operand (of the assignment), it's an expression, it's an operator, but it's not data except perhaps metaphorically. – ikegami Aug 13 '13 at 16:29
  • The last comment is very important. You seem to think operators returns some kind of data which is then evaluated in some context, and that's completely wrong. Data is not evaluated; code is evaluated. When it's said that an array is evaluated in scalar context, it's referring to the *operator* that looks like `@a`, not the array it accesses. – ikegami Aug 13 '13 at 16:30
  • @ikegami - forgive me, I meant, what does the RHS evaluate to? Is it not data? If not, what is it? If it is, how would you classify it (in view of the perldata quotation)? – Ted Hopp Aug 13 '13 at 16:33
  • Re "I meant, what does the RHS evaluate to?", qw() in list context evaluates to a list of scalars, which is to say an ordered bunch of scalars on the stack. – ikegami Aug 13 '13 at 16:35
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/35373/discussion-between-ikegami-and-ted-hopp) – ikegami Aug 13 '13 at 16:39
5

Each of a subroutine's return expressions (i.e. the operand of return statements and any final expressions of a sub) are evaluated in the same context as the subroutine call itself.

sub f {
    ...
    return THIS if ...;
    return THIS if ...;
    ...
    if (...) {
        ...
        THIS
    } else {
        ...
        THIS
    }
}

In this case, the return expression is a list assignment. (@a and qw are operands of the assignment and are thus evaluated before the assignment.) A list assignment in scalar context evaluates to the number of elements to which its right-hand side evaluated.

See Scalar vs List Assignment Operator

ikegami
  • 367,544
  • 15
  • 269
  • 518
3

In Perl, the return value of a subroutine is the last expression evaluated if there is no return statement specified.

From the perlsub docs:

If no return is found and if the last statement is an expression, its value is returned. If the last statement is a loop control structure like a foreach or a while , the returned value is unspecified. The empty sub returns the empty list.

squiguy
  • 32,370
  • 6
  • 56
  • 63
  • 1
    @ikegami - You appear to be misreading (I presume not deliberately) both this answer and mine. Despite your complaints about our answers, neither of us said that "the last expression evaluated is `@a`". It seems clear to me that we are both saying that the last expression is _the assignment to `@a`_, which is exactly what you are saying as well. You say to consider `sub bar { () = qw (10 7 6 8) }`. What conclusion are we supposed to draw from considering it? That it behaves as we have already described? Amazing. – Ted Hopp Aug 12 '13 at 22:56
  • @Ted Hopp, You claimed the list assignment in scalar context returned the result of the LHS in scalar context. That example shows that you're wrong. The rest of your points are addressed under your node where you also brought them up. You should read my post if you want to learn what really happens. [Note that squiguy removed the incorrect part (leaving a partial answer behind). As such, I removed my earlier comment.] – ikegami Aug 13 '13 at 03:34
  • 1
    @ikegami - I did **not** claim that the list assignment in a scalar context returns the result of the LHS in a scalar context. Your example does, indeed, show that I would have been wrong to do so. Congratulations, you've shot down your [straw man](http://www.nizkor.org/features/fallacies/straw-man.html). – Ted Hopp Aug 13 '13 at 05:01
  • @Ted Hopp, The array is the assignment's LHS operand, and an array only evaluates to its number of elements in scalar context, so that's exactly what you said when you said the assignment "evaluates to the array length." Maybe you *meant* something different? – ikegami Aug 13 '13 at 05:39