Search code examples
perl

How can I use Perl's each with a list?


I'm trying to:

#!/usr/bin/env perl

use 5.038;
use warnings FATAL => 'all';
use autodie ':all';
use Devel::Confess 'color';

while (my ($i, $t) = each('a','b','c')) {
    say "$i, $t";
}

but I get an error:

Experimental each on scalar is now forbidden

('a','b','c') is a scalar?

I really like Perl's each on arrays, as I don't have to declare an iterator variable.

I have also tried

while (my ($i, $t) = each(('a','b','c'))) {

while (my ($i, $t) = each(qw('a','b','c'))) {

but get the same error.

while (my ($i, $t) = each(@{ ('a','b','c') }) {

but the above gives an error: Useless use of a constant ("a") in void context which I got from how to solve the “Experimental values on scalar is now forbidden” problem in perl

How can I convince Perl's each that ('a','b','c') is an array?


Solution

  • How can I convince Perl's each that ('a','b','c') is an array?

    You can't, because ('a','b','c') is just a list of string literals (scalars). It is not an array variable.

    Docs for each are clear

    each HASH

    each ARRAY
    ...

    So it wants a variable, either a hash or an array.


    There is also the question of the error that comes up

    but I get an error:

    Experimental each on scalar is now forbidden

    ('a','b','c') is a scalar?

    First off, the full error message that I get for such code

    perl -wE'while( my ($i, $t) = each(qw(a b c)) ) { say "$i, $t" }'
    

    is instructive

    Experimental each on scalar is now forbidden at -e line 1.
    Type of arg 1 to each must be hash or array (not list) at -e line 1, near "qw(a b c)) "
    Execution of -e aborted due to compilation errors.
    

    The function each is prototyped,

    perl -wE'say prototype "CORE::each"'  #-->  \[%@]
    

    so it needs one item which need be a hash or an array variable. By passing it a list we have a mismatch which is caught at compile time, and is fatal. So right there it's game over.

    However, as an additional courtesy we also get that message about "experimental each on scalar".

    If this mismatch in prototype were to pass (not be fatal), the list 'a', 'b', 'c' would then be an expression to be evaluated, which yields either three scalars or one scalar (by comma operator the first two items are thrown away and the expression returns 'c', or, if precedence is the other way round, 'a' is returned and the rest discarded), depending on context.

    In either case a scalar would be intended for each, what used to be allowed then warned against then outright forbidden. Now each accepts only a (hash/array) variable, not an expression, and in reference to this history we also (still) get an extra message.