Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl: constants and compile-time vs runtime hash lookups?

In Perl 5.26, constant-based hash lookups appear to be resolved at compile-time, not runtime. How can I enforce it to be resolved at runtime?

Consider the following reduced testcase, boiled down from a hash-based state-machine I was trying to write, where the key is the state identifier and the value is the state function.

use constant {
    STATE_1 => 1,
    STATE_2 => 2,
};

my %fsm;

%fsm = (
    STATE_1, sub {
        $fsm{STATE_2}->(@_);
        return STATE_2;
    },
    STATE_2, sub {
        return STATE_1;
    }
);

my $state = STATE_1;

$state = $fsm{$state}->();

Note that in STATE_1, I'm trying to call the STATE_2 function.

However, at runtime I get this:

Can't use an undefined value as a subroutine reference at ./self-reference-hash.pl line 15.

Which indicates that the $fsm{STATE_2}->(@_); line in STATE_1 is undefined. And indeed, at the time where this line first appears, the STATE_2 function isn't defined yet, but I was counting on hash lookups being resolved at runtime.

If I instead replace $fsm{STATE_2}->(@_); with my $tmp = STATE_2; $fsm{$tmp}->(@_); then it works as expected, which seems hacky.

Is there a cleaner way to do this?

like image 360
John de Largentaye Avatar asked Dec 11 '22 05:12

John de Largentaye


1 Answers

The source of this problem is actually explained in Perl's doc about constant, and it's not about runtime vs compile-time, but about Perl magically quoting barewords in some contexts:

You can get into trouble if you use constants in a context which automatically quotes barewords (as is true for any subroutine call). For example, you can't say $hash{CONSTANT} because CONSTANT will be interpreted as a string. Use $hash{CONSTANT()} or $hash{+CONSTANT} to prevent the bareword quoting mechanism from kicking in. Similarly, since the => operator quotes a bareword immediately to its left, you have to say CONSTANT() => 'value' (or simply use a comma in place of the big arrow) instead of CONSTANT => 'value' .

The listed workarounds resolve the issue.

like image 132
John de Largentaye Avatar answered Dec 21 '22 23:12

John de Largentaye