Who has the best state implementation?

nicholas on 2008-04-29T10:07:40

Who has the best state implementation? (For some arbitrary definition of "best".) Let's see:

$ cat state.pl 
sub foo {
    state $bar = "Pie";
    say $bar;
    $bar = "Good";
}
foo();
foo();
Rakudo?
$ ./parrot languages/perl6/perl6.pbc state.pl 
scope declarator 'state' not implemented at line 2, near "= \"Pie\";\n "
current instr.: 'parrot;PGE::Util;die' pc 120 (runtime/parrot/library/PGE/Util.pir:82)
called from Sub 'parrot;Perl6;Grammar;Actions;_block1900' pc 107647 (src/gen_actions.pir:5109)
called from Sub 'parrot;Perl6;Grammar;Actions;_block1890' pc 107410 (src/gen_actions.pir:5015)
called from Sub 'parrot;Perl6;Grammar;Actions;_block1864' pc 107316 (src/gen_actions.pir:4975)
called from Sub 'parrot;Perl6;Grammar;Actions;scope_declarator' pc 105807 (src/gen_actions.pir:4402)
called from Sub 'parrot;Perl6::Grammar;scope_declarator' pc 73809 (src/gen_grammar.pir:22436)
called from Sub 'parrot;Perl6::Grammar;noun' pc 66663 (src/gen_grammar.pir:19982)
called from Sub 'parrot;Perl6::Grammar;term' pc 62462 (src/gen_grammar.pir:18460)
called from Sub 'parrot;PGE::OPTable;parse' pc 1998 (compilers/pge/PGE/OPTable.pir:532)
called from Sub 'parrot;Perl6::Grammar;statement' pc 18468 (src/gen_grammar.pir:3117)
called from Sub 'parrot;Perl6::Grammar;statementlist' pc 15720 (src/gen_grammar.pir:2170)
called from Sub 'parrot;Perl6::Grammar;statement_block' pc 13578 (src/gen_grammar.pir:1384)
called from Sub 'parrot;Perl6::Grammar;block' pc 14687 (src/gen_grammar.pir:1795)
called from Sub 'parrot;Perl6::Grammar;routine_def' pc 48620 (src/gen_grammar.pir:13549)
called from Sub 'parrot;Perl6::Grammar;routine_declarator' pc 47075 (src/gen_grammar.pir:13013)
called from Sub 'parrot;Perl6::Grammar;noun' pc 66887 (src/gen_grammar.pir:20052)
called from Sub 'parrot;Perl6::Grammar;term' pc 62462 (src/gen_grammar.pir:18460)
called from Sub 'parrot;PGE::OPTable;parse' pc 1998 (compilers/pge/PGE/OPTable.pir:532)
called from Sub 'parrot;Perl6::Grammar;statement' pc 18468 (src/gen_grammar.pir:3117)
called from Sub 'parrot;Perl6::Grammar;statementlist' pc 15720 (src/gen_grammar.pir:2170)
called from Sub 'parrot;Perl6::Grammar;statement_block' pc 13578 (src/gen_grammar.pir:1384)
called from Sub 'parrot;Perl6::Grammar;TOP' pc 10420 (src/gen_grammar.pir:204)
called from Sub 'parrot;PCT::HLLCompiler;parse' pc 564 (src/PCT/HLLCompiler.pir:348)
called from Sub 'parrot;PCT::HLLCompiler;compile' pc 440 (src/PCT/HLLCompiler.pir:291)
called from Sub 'parrot;PCT::HLLCompiler;eval' pc 755 (src/PCT/HLLCompiler.pir:450)
called from Sub 'parrot;PCT::HLLCompiler;evalfiles' pc 1067 (src/PCT/HLLCompiler.pir:587)
called from Sub 'parrot;PCT::HLLCompiler;command_line' pc 1246 (src/PCT/HLLCompiler.pir:676)
called from Sub 'parrot;Perl6::Compiler;main' pc 8860 (perl6.pir:183)
Pugs?
$ ./pugs state.pl 
Pie
Pie
Perl 5
$ /usr/local/perl-5.10.0/bin/perl -Mfeature=:5.10 state.pl
Pie
Good

Yes, strange as it may seem, Perl 5 has the most complete implementation of Perl 6's state†. Only Perl 5 performs an initialisation via = once. I blame Rafael, Dave and me.

† At least this week. For some value of this week. Until someone reads this Perl blog and gets hacking.


Odd - Pug's state worked correctly back in 2005

Limbic Region on 2008-04-29T13:15:28

See http://svn.pugscode.org/pugs/examples/cashiers.pl

# Demo of the state() variable declaration.
# This is also a neat way of doing OO without actually having OO available.
#
# Please remember to update t/examples/examples.t and rename
# examples/output/cashiers if you rename/move this file.
 
use v6-alpha;
 
sub gen_cashier () {
    # This variable corresponds to a class variable.
    # It is shared across all "instances" of gen_cashier().
    state $cash_in_store = 0;
 
    # One could add my() variables here, which correspond to instance variables.
    # These would not be shared.
 
    # Finally, we return a hashref which maps method names to code.
    return {
        add => { $cash_in_store += $^amount },
        del => { $cash_in_store -= $^amount },
        bal => { $cash_in_store             },
    };
}
 
my $drawer;
$drawer[$_] = gen_cashier() for 1..3;
 
$drawer[1]<add>( 59 );
$drawer[2]<del>( 17 );
say $drawer[3]<bal>();  # This should say "42"
It was written back in July of 2005 before pugs had OO.

I don't have pugs installed at work to test and I can't remember the right fu to get the evalbot in #perl6 to test for me

Re:Odd - Pug's state worked correctly back in 2005

nicholas on 2008-04-29T14:02:03

I don't think that it did. Certainly, that example is not a good enough test, because it makes all three calls to gen_cashier before it uses any of the closures, so it makes no difference how many times that assignment of 0 is performed. If I re-write it like this

use v6-alpha;

sub gen_cashier () {
    # This variable corresponds to a class variable.
    # It is shared across all "instances" of gen_cashier().
    state $cash_in_store = 0;

    # One could add my() variables here, which correspond to instance variables.
    # These would not be shared.

    # Finally, we return a hashref which maps method names to code.
    return {
        add => { $cash_in_store += $^amount },
        del => { $cash_in_store -= $^amount },
        bal => { $cash_in_store             },
    };
}

gen_cashier()<add>( 59 );
gen_cashier()<del>( 17 );
say gen_cashier()<bal>();  # This should say "42"

then I get the wrong answer:

$ ./pugs examples/cashiers.pl
0

If I remove the assignment of 0, and rely on undef becoming 0:

sub gen_cashier () {
    # This variable corresponds to a class variable.
    # It is shared across all "instances" of gen_cashier().
    state $cash_in_store;

    # One could add my() variables here, which correspond to instance variables.
    # These would not be shared.

    # Finally, we return a hashref which maps method names to code.
    return {
        add => { $cash_in_store += $^amount },
        del => { $cash_in_store -= $^amount },
        bal => { $cash_in_store             },
    };
}

gen_cashier()<add>( 59 );
gen_cashier()<del>( 17 );
say gen_cashier()<bal>();  # This should say "42"

then I get back to the right answer:

./pugs -w examples/cashiers.pl
42

state is doing something though here - a single variable is being shared between all 3 closures. To get the same effect with my I have to hoist my $cash_in_store outside of sub gen_cashier

In conclusion, I don't think that state in Pugs has regressed - it never worked quite as well the example implied.

Rakudo now works

ajs on 2009-10-05T19:43:38

This now works in rakudo, FWIW. Tested with current git version as of this weekend (Oct 2009).