state
ErrorsCollection

state

Synthesised documentation from language/variables

From language/variables

See Original text in context

state declares lexically scoped variables, just like my. However, initialization happens exactly once, the first time the initialization is encountered in the normal flow of execution. Thus, state variables will retain their value across multiple executions of the enclosing block or routine.

Therefore, the subroutine

sub a {
    state @x;
    state $l = 'A';
    @x.push($l++);
};
 
say a for 1..6;

will continue to increment $l and append it to @x each time it is called. So it will output:

[A]
[A B]
[A B C]
[A B C D]
[A B C D E]
[A B C D E F]

Since they have a lexical scope, they are tied to the block in which they are declared.

sub foo () {
  for 0..1 {
    state $foo = 1;
    say $foo++;
  }
};
foo;  # OUTPUT: «1␤2␤» 
foo;  # OUTPUT: «1␤2␤» 

In this case, a new state variable is created every time the block that runs the for loop is entered, which is why the state variable is reset in every call to foo.

This works per "clone" of the containing code object, as in this example:

({ state $i = 1$i++.say} xx 3).map: {$_(), $_()}# says 1 then 2 thrice 

Note that this is not a thread-safe construct when the same clone of the same block is run by multiple threads. Also remember that methods only have one clone per class, not per object.

As with my, a declaration of multiple state variables must be placed in parentheses which can be omitted for a single variable.

Many operators come with implicit binding which can lead to actions at a distance.

Use .clone or coercion to create a new container that can be bound to.

my @a;
my @a-cloned;
sub f() {
    state $i;
    $i++;
    @a       .push: "k$i" => $i;
    @a-cloned.push: "k$i" => $i.clone;
};
 
f for 1..3;
say @a;        # OUTPUT: «[k1 => 3 k2 => 3 k3 => 3]␤» 
say @a-cloned# OUTPUT: «[k1 => 1 k2 => 2 k3 => 3]␤»

State variables are shared between all threads. The result can be unexpected.

sub code(){ state $i = 0say ++$i$i };
await
    start { loop { last if code() >= 5 } },
    start { loop { last if code() >= 5 } };
 
# OUTPUT: «1␤2␤3␤4␤4␤3␤5␤» 
# OUTPUT: «2␤1␤3␤4␤5␤» 
# many other more or less odd variations can be produced