Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl BEGIN failed compilation because scalar @list

Tags:

perl

I am new to Perl. I find out that code as follows cannot run:

#! perl -T

use strict;
use warnings;

BEGIN {
    my @classes = qw(Animal Cow Sheep Horse Mouse);
    use Test::More tests => scalar @classes;
}

If I change scalar @classes to 5, it is ok. If I change use Test::More tests => scalar @classes; to print scalar @classes;, it is ok. But when they are together, they are wrong. Why?

like image 682
roger Avatar asked Nov 18 '25 11:11

roger


2 Answers

The idiomatic way to do this would be to use the plan function instead of specifying the number of tests in the use statement:

use Test::More;
my @classes = qw(Animal Cow Sheep Horse Mouse);
plan(tests => scalar @classes);

If you insist on specifying the number of tests in the use, you need either

my @classes;
BEGIN {
    @classes = qw(Animal Cow Sheep Horse Mouse);
}
use Test::More tests => scalar @classes;

or

BEGIN {
    my @classes = qw(Animal Cow Sheep Horse Mouse);
    require Test::More;
    Test::More->import(tests => scalar @classes);
}

The problem is that use is evaluated at compile-time. You put it inside a BEGIN block, which is also evaluated at compile-time, but the BEGIN block has its own compilation phase.

Because the use is executed before the rest of the BEGIN block, what you wrote is equivalent to

BEGIN {
    my @classes;
    require Test::More;
    Test::More->import(tests => scalar @classes);
    @classes = qw(Animal Cow Sheep Horse Mouse)
}

That's why it complains about you trying to plan 0 tests.

like image 116
cjm Avatar answered Nov 20 '25 04:11

cjm


This is because use MODULE is exactly equivalent to BEGIN { require Module; Module->import( LIST ); } (see perldoc -f use).

I suspect the BEGIN within a a BEGIN block is causing the problem, and indeed, replacing the code with

#! perl -T

use strict;
use warnings;

BEGIN {
    my @classes = qw(Animal Cow Sheep Horse Mouse);
    require Test::More; Test::More->import( tests => scalar @classes );
}

seems work fine.

like image 33
kbenson Avatar answered Nov 20 '25 04:11

kbenson