Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

something between "state" and "my"

0 views
Skip to first unread message

Dave Whipp

unread,
Feb 3, 2006, 12:40:45 AM2/3/06
to perl6-l...@perl.org
(from p6i)

Larry Wall wrote:
> On Thu, Feb 02, 2006 at 07:12:08PM +0100, Leopold Toetsch wrote:
> : >... Anyway,
> : >the P6 model of "state" is more like a persistent lexical than like
> : >C's static.
> :
> : Sorry for my dumb question - what's the difference then? (Besides that C
> : dosn't have closures ;)
>
> That *is* the difference.
[...]

I was thinking about this discussion on p6i, and I started thinking that
there's something between "my" and state: a "state" variable that is
created/initialized on each invocation of a sub but only if it's not
already in the dynamic scope (i.e. if its not a recursive call). A
slightly silly example of its use (using "temp state" as the quantifier)
would be:

sub factorial(Int $x) {
temp state Int $result = 1;
$result *= $x;
factorial $x-1 if $x > 2;
return $result if want;
}
say factorial 6;

This code is essentially the same as any other recursive factorial
function, except that it doesn't use call-stack semantics to maintain
its state. (I know P6 will do tail recursion, but sometimes I find
myself building complex args/return values to pass state from one
iteration to the next.)

Equivalent code without this feature is:

sub factorial(Int $x) {
my Int $result = 1;
my sub fact1(Int $x) {
$result *= $x;
fact1 $x-1 if $x > 2;
}
fact1 $x
return $result;
}

Dave.

Luke Palmer

unread,
Feb 3, 2006, 1:45:23 AM2/3/06
to Dave Whipp, perl6-l...@perl.org
On 2/3/06, Dave Whipp <da...@whipp.name> wrote:
> sub factorial(Int $x) {
> temp state Int $result = 1;
> $result *= $x;
> factorial $x-1 if $x > 2;
> return $result if want;
> }
> say factorial 6;

That's precisely what "env" variables are for. The right way:

sub factorial(Int $x) {
env $result = 1;
my sub fact(Int $x) {
$+result *= $x;
fact($x - 1) if $x > 2;
return $result;
}
fact($x);
}

Of course, you can view env variables as implicit parameters. Given
that, this function might be able to reduce to:

sub factorial(Int $x) {
env $+result = 1; # expecting $+result
# param, default to 1
$+result *= $x;
fact($x - 1) if $x > 2;
return $result;
}

Luke

Larry Wall

unread,
Feb 3, 2006, 2:58:49 PM2/3/06
to perl6-l...@perl.org
: }

Hmm, that won't work in my current mental model, where an "env" is
used only in the outermost dynamic scope to declare the existence of
that outermost scope, and within that scope it behaves exactly like a
"my" variable. But that means that the assignment happens every time,
not as some kind of default.

If you don't have an outermost scope declarator, you've just basically
reinvented a less efficient version of globals and "temp", since "env
$+result" would always have to assume there was an outer dynamic scope
and scan outward to the root dynamic scope.

But that's just my current mental model, which history has shown
is subject to random tweakage. And maybe "env $+result" could be a
special squinting construct that does create-unless-already-created.
Doesn't feel terribly clean to me though. If we stick with the +
twigil always meaning at least one CALLER::, then clarity might be
better served by

env $result := $+result // 1;

assuming that $+result merely returns undef in the outermost env context.

Larry

Dave Whipp

unread,
Feb 3, 2006, 3:41:47 PM2/3/06
to perl6-l...@perl.org
Larry Wall wrote:

> But that's just my current mental model, which history has shown
> is subject to random tweakage. And maybe "env $+result" could be a
> special squinting construct that does create-unless-already-created.
> Doesn't feel terribly clean to me though. If we stick with the +
> twigil always meaning at least one CALLER::, then clarity might be
> better served by
>
> env $result := $+result // 1;
>
> assuming that $+result merely returns undef in the outermost env context.

Wouldn't that bind $result to a constant at the outermost scope -- and
therefore to that same constant in all inner scopes? If so, then later
attempts to assign $result would be an error.

Larry Wall

unread,
Feb 3, 2006, 4:19:38 PM2/3/06
to perl6-l...@perl.org

Hmm, well, it wouldn't work anyway since env variables are readonly
by default outside their "my" scope. I ought to at least have said

env $result is rw := $+result // 1;

As for

my $answer := 42;

I would hope that binding a constant to a rw location is smart enough
to make an anonymous rw copy (or COW). I think that's what most
existing Perl programmers would expect. I'm sure a C++ programmer would
argue it the other way though.

But whichever way that goes, certainly if you want to make $answer
a constant, the current design encourages you to do it explicitly with

constant $answer = $mumble;

rather than as an accidental side effect of binding a value that just
happens to be a constant. And I think a good argument can be made that

my $foo := "some text";

is a great way of sharing "some text" among all default instances of $foo,
whereas

my $foo = "some text";

would be required to force a copy, at least in the abstract.
Of course, the existence of a COW string implementation can be taken
as an argument either way. It really kind of depends on whether you
see "some text" as an object or as primitive data that autoboxes when
a container reference is requested.

Larry

0 new messages