On 10/2/2014 16:03, Elizabeth Mattijsen wrote:
On 01 Oct 2014, at 07:48, Father Chrysostomos <spr...@cpan.org> wrote:
Does ‘state’ govern ‘:=’ the way it governs ‘=’?  In other words, just as this:

    state $x = 1;

only assigns to $x once (per closure), does the same apply to this?

    state $x := $y;

I can’t find anything in the specs that implies that it does.

The reason I ask is that I am currently implementing binding for Perl 5, but 
the syntax is different—

    \$x = \$y;

(The reason for the different syntax is that, when we tried to use :=, we could 
not find a coherent way to handle edge cases [e.g., flattening vs not 
flattening].  Reusing existing Perl 5 syntax seemed the most straightforward 
and intuitive approach.)

—and I am debating whether \state $x = \$y should bind only once or every time 
the surrounding code is executed.  I could argue it either way (though I am 
leaning toward the latter), so I thought to find out what Perl 6 does.
It would seem that binding state variables will be something that will be 
prohibited in Perl 6, until such time we find a good use case for it.


[15:55:36] <lizmat>        well, all of this was because of a question of 
Father Chrysostomos (a very productive p5p contributor) on p6l
[15:57:01] <jnthn>         OK. Well, I'll leave it at, I'm happy enough with 
the current semantics, so unless TimToady++ feels they have to chnage, then I'm not 
inclined to do much about the status quo.
[15:57:44] <jnthn>         (Where by "the current semantics" I mean, what Moar 
does, and I'm about certain what we do on JVM. I don't actually know how things are on Parrot.)
[15:57:59] <lizmat>        eh, but the current semantics silently do the wrong 
thing, no ?
[15:59:11] <jnthn>         lizmat: Depends how you define the semantics of 
state.
[15:59:44] <jnthn>         lizmat: Note that if you go binding a temp or let 
var you are in equal trouble.
[16:00:03] moritz        wouldn't mind compile-time disallowing rebinding 
temp/let/state vars
[16:00:05] <jnthn>         'cus those are certainly about value, not container
[16:00:14] <lizmat>       moritz +1
[16:00:18] <jnthn>         I took state to be wanting the same semantics
[16:00:31] <jnthn>         Yeah, I could go with a conservative approach of "just 
disallow it"
[16:00:53] <lizmat>        I'll answer FC

To expand a little, all of state/temp/let are implemented under the assumption that you'll be doing assignment to the container you applied them to. That is, when I:

    temp $x;

Then I'm really saying "stash away a pair (the-cont = $x, current-value = the value in $x), and at block LEAVE time then do the-cont = old-value". It's the same container throughout, and if you re-bind $x then temp has no clue about it. For state, containers are created at first entry to a given closure clone, stashed away in the closure's code object, and those same containers are used in the frames (specifically, lexical storage) of future invocations of the same closure.

Generally in Perl 6, binding is a quite low-level operation. An operation:

    $x := $y;

Might be JITted to just a couple of instructions (perhaps even if $x has a static type constraint that needs checking, since type specialization might prove the check isn't needed). Binding can be understood as directly replacing the contents of a slot (that is, just setting a pointer), and has no effect on any container that used to be there. Since state is implemented by keeping another reference to the container in the closure's code object, re-binding a state variable in a call frame will have no effect beyond the lifetime of that frame:

> sub foo() { state $x = 42; say $x++; $x := 99; say $x; }; foo() for ^5
    42
    99
    43
    99
    44
    99
    45
    99
    46
    99

It's also worth noting that:

    state $x = 42;

And a later:

    $x = 42;

Are parsed rather differently. The same goes for := and ::=. The former kind of construct is parsed as a declarator with an initializer; the latter is parsed as the familiar infix operators. Curiously, since we figure out what to do by declarator scope (so a different code-path for state than my), it turns out that := and ::= initializers on a state var are completely ignored at present.

I suspect instead of ignoring them, we'll go down to line of giving an error on:

    state $x := something;

...because it's hard to imagine it being anything except programmer error. That is, unless Larry comes along and declares that state should have got "save what's in the lexpad back to the per-closure storage at scope exit" semantics, in which case it would do something arguably useful...and increase the cost of state vars, frustrate inlining (in a perhaps fixable way), and make something once immutable become mutable...you might imagine I'm hoping we don't go this way. :-)

But to answer the original question, if we *do* end up doing something that runs code in a "state $x := ..." rather than complain about it, then it will surely be once per closure clone, not every time, because that form is parsed as an initializer, and initializers are subject to thunky behavior picked by scope declarator.

Hope this helps,

/jnthn

Reply via email to