Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't we initialize state arrays/hashes in list context?

There is a restriction on arrays and hashes as state variables. We can't initialize them in list context as of Perl 5.10:

So

state @array = qw(a b c); #Error!

Why is it so? Why this is not allowed?

We can use state arrays and initialize them by this way

state @numbers;
push @numbers, 5;
push @numbers, 6;

but why not directly do it by state @numbers = qw(5 6);

Why doesn't Perl allow it?

like image 325
Chankey Pathak Avatar asked Jul 15 '11 04:07

Chankey Pathak


3 Answers

According to perldiag, support for list context initialization is planned for a future release:

  • Initialization of state variables in list context currently forbidden
    (F) Currently the implementation of "state" only permits the initialization of scalar variables in scalar context. Re-write state ($a) = 42 as state $a = 42 to change from list to scalar context. Constructions such as state (@a) = foo() will be supported in a future perl release.

According to this message about the change that made this an error:

For now, forbid all list assignment initialisation of state variables, as the precise semantics in Perl 6 are not clear. Better to make it a syntax error, than to have one behaviour now, but change it later. [I believe that this is the consensus. If not, it will be backed out]

You could always use an arrayref instead:

state $arrayRef = [qw(a b c)];

Note that your example of

state @numbers;
push @numbers, 5;
push @numbers, 6;

does not mean the same thing that state @numbers = qw(5 6) would (if it worked). A state variable is only initialized once, but your code would push 5 & 6 onto the array every time that code was executed.

like image 69
cjm Avatar answered Oct 12 '22 18:10

cjm


Horrible workaround:

state @array;
state $array_is_initialized;
unless ($array_is_initialized) {
    $array_is_initialized = 1;
    @array = (1,2,3);
}
like image 43
ysth Avatar answered Oct 12 '22 20:10

ysth


It simply hasn't been written, because it's kind of hard, and getting it to work for scalars was considered to be more important. There's an opcheck (Perl_ck_sassign in op.c) that recognizes when the left side of an assignment is a padsv op referring to a newly-declared state variable and wraps it in a special once op that makes sure that the assignment only happens once -- but it doesn't even attempt to recognize list assignments, probably due to the difficulty of breaking up a (state $a, my $b, state $c) = (1, 2, 3) type construct. Funny though, it seems like state @a = qw(blah blah blah) would be easy enough, and clearly it's a less pathological case than the other list assignment variant.

like image 5
hobbs Avatar answered Oct 12 '22 20:10

hobbs