Skip to content

Instantly share code, notes, and snippets.

@dha
Last active September 15, 2015 18:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dha/8009c28d7bf2d1ca8875 to your computer and use it in GitHub Desktop.
Save dha/8009c28d7bf2d1ca8875 to your computer and use it in GitHub Desktop.
Proposed documentation for C<state>
=begin pod
C<state> declares lexically scoped variables, just like C<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
=begin code
sub a {
state @x = 1, 1;
@x.push(1, 1)
}
=end code
will continue to append each time it is called. So,
=begin code
say a;
say "next";
say a;
say "next";
say a;
=end code
will output
=begin code
[1 1 1 1]
next
[1 1 1 1 1 1]
next
[1 1 1 1 1 1 1 1]
=end code
Also, just like C<my>, declaring multiple variables must be placed in
parentheses and for declaring a single variable, parentheses may be
omitted. Within a parenthesized list, C<$> can be used as a dummy
placeholder.
In fact, C<$> can be used as an anonymous state variable without an explicit C<state> declaration.
=begin code
perl6 -e 'sub foo() { say ++$ }; foo() for ^3'
=end code
produces
=begin code
1
2
3
=end code
Furthermore, state variables are not required to exist in
subroutines. You could, for example, use C<$> in a one-liner to
number the lines in a file.
=begin code
perl6 -ne 'say ++$ ~ " $_"' example.txt
=end code
Finally, if you were to use multiple anonymous state variables, they would
fuction independently.
=begin code
perl6 -e '{ say ++$; say ++$ } for ^5'
=end code
would produce
=begin code
1
1
2
2
3
3
4
4
5
5
=end pod
@lizmat
Copy link

lizmat commented Sep 14, 2015

Excellent!

The only thing I miss is an explanation of the scoping rules of state, e.g. when used in a block, or with recursive calls. As I'm unsure myself how this works exactly, some research / community support may be necessary to get this together.

@raiph
Copy link

raiph commented Sep 14, 2015

state variables will retain their value across multiple executions of the enclosing block or routine.

I'm not sure of the official terminological distinction between blocks and closures, but let's say a "source block" is a chunk of source code and its enclosing pair of braces and a "run-time block" is the executabble equivalent at run-time. Then one needs to be aware that, while there's usually a 1-to-1 correspondence, that's not always the case -- there can be multiple run-time copies of the same source block in some scenarios. Examples:

sub foo { ++$ }; say foo for ^2
1
2
say { ++$ }() foo for ^2
1
1

This is called "closure cloning" in http://design.perl6.org/S04.html. (Note, this is not the same as other forms of cloning such as object cloning.) Probably gets especially interesting in a multi-threaded context.

Within a parenthesized list, C<$> can be used as a dummy placeholder.

I don't think a dummy placeholder is a state variable. I don't think that bit belongs on this page.

In fact, C<$> can be used as an anonymous state variable in subroutines without a C declaration.

Not just in subroutines but in any code where a state variable is valid:

perl6 -e 'say ++$ for ^2'

I think this deserves its own subhead ("Anonymous state variables") or somesuch.

@dha
Copy link
Author

dha commented Sep 14, 2015

Updated gist to cover the issues noted.

@perlpilot
Copy link

Excellent! The only thing I would change would be the first example using different numbers for the initialization versus the subsequent pushes. dha++

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment