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

I wanted to ask if I misunderstood following sentences from "Learning Perl" book p.117:

"Now, when Perl evaluates each %hash, there are no more key-value pairs available so each has to return an empty list.‖ The empty list is assigned to ($key, $value), so $key gets undef, and $value also gets undef.

But that hardly matters, because you’re evaluating the whole thing in the conditional expression of the while loop. The value of a list assignment in a scalar context is the number of elements in the source list—in this case, that’s 0. Since 0 is a false value, the while loop is done, and execution continues with the rest of the program."

while ( ($key, $value) = each %hash ) { print "$key => $value\n"; }
In my opinion, after "($key, $value)" are assigned to "()" and list becomes "(undef, undef)", scalar context takes only the last element of the list, that means 2nd "undef". Am I wrong?

use 5.010; say '[', scalar (3..4), ']'; say '[', scalar (undef, undef), ']'; say '[', scalar (undef, 1, undef, 5), ']'; @a = (3..4); @b = (undef, undef); @c = (undef, 1, undef, 5); say '[', scalar @a, ']'; say '[', scalar @b, ']'; say '[', scalar @c, ']'; say '[', scalar 3..4, ']';
OUTPUT:
[] [] [5] [2] [2] [4] [34]

Replies are listed 'Best First'.
Re: each %hash: scalar context of list (undef, undef) is false
by choroba (Cardinal) on Nov 22, 2014 at 18:00 UTC
    Comma in scalar context returns the right operand. List assignment, though, as your citation says, returns the number of elements in the source list.
    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re: each %hash: scalar context of list (undef, undef) is false
by Eily (Monsignor) on Nov 22, 2014 at 18:16 UTC

    With $length = (4,5,6) the thing that gets evaluated in scalar context is (4,5,6), which a list, and so indeed, $length here will be assigned the value '6'. But if you apply scalar context to something else, the result is not always the last element. For exemple in $length = @array the right side is an array, not a list (the two notions are close but not identical in perl, you can see an array as a list encapsulated in an object that changes its behavior), and you get the length. And, another case, reverse in list context will return a list of elements, but in scalar context does not just return the last elements, but the concatenated reverse string.

    The reason that the while(($key, $val) = each %hash) works is because the expression that gets evaluated in scalar context is not a list, but an assignment (it's not just data, it's an action), and list assignments, unlike simple lists eval to the size of the list. You can see ($key, $val) = each %hash as a simpler way to write AssignTo(key => \$key, val => $val, from => \%hash) (this does not work), where AssignTo is a fonction that returns the number of elements 'removed' from the hash. If indeed, the while tested the last value, and not the number of elements, a hash like (1 => 0, 2 => 0) would fail to be read by the loop, because $val would be 0, which is false.

    The difference between just a list and a list assignment is used in this kind of code: my $numberOfMatches = () = /regex/g; Where the right part is evaluated first (so the matches of the regex are copied to (), ie thrown away), and then my $numberOfMatches = LIST_ASSIGNMENT is evaluated, where the value of LIST_ASSIGNMENT is the number of elements that where redirected towards ().

    Edit: I feel like I wrote too much an wasn't really clear I hope I didn't confuse you even more ...

Re: each %hash: scalar context of list (undef, undef) is false
by LanX (Saint) on Nov 22, 2014 at 18:26 UTC
    ... additionally ...

     scalar (3 .. 4) in scalar context is the flip flop operator, not a range and its false hence empty string.

     scalar 3 .. 4 is just  (scalar 3) .. 4

    Cheers Rolf

    (addicted to the Perl Programming Language and ☆☆☆☆ :)

Re: each %hash: scalar context of list (undef, undef) is false
by ikegami (Patriarch) on Nov 22, 2014 at 20:09 UTC

    In

    while ( ($key, $value) = each %hash ) { ... }

    The operator the while is evaluating is the list assignment operator. ($key, $value) and each %hash are the operands to the list assignment operator. It's as if you have list_assign(list(lexical_sv('key'), lexical_sv('value')), each(lexical_hv('hash'))). As you can see, the list assignment operator is what is in scalar context, not ($key, $value). To see what the list assignment operator returns in scalar context, see Mini-Tutorial: Scalar vs List Assignment Operator, but it's easy to figure out.

    >perl -E"say scalar( ($x,$y)=() )" 0 >perl -E"say scalar( ($x,$y)=(undef) )" 1 >perl -E"say scalar( ($x,$y)=(undef,undef) )" 2 >perl -E"say scalar( ($x,$y)=(undef,undef,undef) )" 3
Re: each %hash: scalar context of list (undef, undef) is false
by Anonymous Monk on Nov 22, 2014 at 18:31 UTC
    In my opinion, after "($key, $value)" are assigned to "()" and list becomes "(undef, undef)", scalar context takes only the last element of the list, that means 2nd "undef". Am I wrong?

    Compare:

    $ perl -E 'say scalar ( ($a, $b) = () )' 0 $ perl -E 'say scalar ( ($a, $b) = (undef, undef) )' 2
      Thanks for all of you!
      That's a bit difficult, but I'll try to understand, memorize.