Home > Software design >  Why "Type of argument to each on reference must be unblessed hashref or arrayref at test.pl lin
Why "Type of argument to each on reference must be unblessed hashref or arrayref at test.pl lin

Time:04-07

I don't understand the error message

Type of argument to each on reference must be unblessed hashref or arrayref at test.pl line 17.

for this test case (extracted from a larger module):

BEGIN { our $RE_timestamp = qr/whatever/; }

# check Regular expressions for TIMESTAMP
use constant _TEST_TIMESTAMPS => (        # from "6.2.3.1.  Examples"
        '1985-04-12T23:20:50.52Z' => 1,
        '1985-04-12T19:20:50.52-04:00' => 1,
        '2003-10-11T22:14:15.003Z' => 1,
        '2003-08-24T05:14:15.000003-07:00' => 1,
        '2003-08-24T05:14:15.000000003-07:00' => 0,        # invalid!
        '-' => 1                        # NILVALUE
);

UNITCHECK
{

    # from "6.2.3.1.  Examples"
    while (my ($str, $valid) = each _TEST_TIMESTAMPS) {
        if ($valid) {
            die "timestamp ($str) is not valid\n"
                if ($str !~ /^${RE_timestamp}$/o);
        } else {
            die "timestamp ($str) is valid\n"
                if ($str =~ /^${RE_timestamp}$/o);
        }
    }
}

Most of all I got the error in Perl 5.18.2, but when I checked on another machine using Perl 5.26.1, there was no error message at all!

So can I make the code work with the older Perl 5.18, too?

Ugly Work-Around

Experimenting I found out that each (my %h = _TEST_TIMESTAMPS) did not help, but when using my %h = _TEST_TIMESTAMPS; and then each %h, then the error was gone.

Still I don't understand what's going on (before using constants I had local my hashes used inside UNITCHECK. Obviously I'd like to use package-level constants instead.

CodePudding user response:

The constant produced by the constant pragma is really a subroutine ("in the current implementation", as docs say. (See Technical Notes and Bugs.) Thus, I guess, they aren't what the error message says is required, hashref (unblessed) or arrayref.

Swapping the const for, say, Const::Fast, seems to confirm this since it then works

use warnings;
#use strict;         # for undeclared $RE_timestamp used in regex (typos)
use feature 'say';

use Const::Fast;

BEGIN { our $RE_RE_timestamp = qr/whatever/; }

# check Regular expressions for TIMESTAMP
BEGIN {
    const our %_TEST_TIMESTAMPS => (        # from "6.2.3.1.  Examples"
        '1985-04-12T23:20:50.52Z' => 1,
        '1985-04-12T19:20:50.52-04:00' => 1,
        '2003-10-11T22:14:15.003Z' => 1,
        '2003-08-24T05:14:15.000003-07:00' => 1,
        '2003-08-24T05:14:15.000000003-07:00' => 0,        # invalid!
        '-' => 1                        # NILVALUE
    );  
}

UNITCHECK
{
    say "$_ => $_TEST_TIMESTAMPS{$_}" for keys %_TEST_TIMESTAMPS; 
    # from "6.2.3.1.  Examples"
    while (my ($str, $valid) = each %_TEST_TIMESTAMPS) {
        if ($valid) {
            die "timestamp ($str) is not valid\n"
                if ($str !~ /^${RE_timestamp}$/o);
        } else {
            die "timestamp ($str) is valid\n"
                if ($str =~ /^${RE_timestamp}$/o);
        }

Lexicals introduced with Const::Fast must be assigned at declaration (and of course cannot be reassigned later) so that has to be an our variable (unfortunately in my book) since it need be in a BEGIN block.

This does work.

As for why this isn't an issue in later Perls, I suppose that the requirement for it to be a hashref or arrayref got dropped at some point. (I can't check that right now.)


Note that you have a typo, declaring $RE_RE_timestamp but using $RE_timestamp.

CodePudding user response:

Try to unbless _TEST_TIMESTAMPS like below before calling each:

use Data::Structure::Util qw(unbless);

unbless(_TEST_TIMESTAMPS);
  • Related