Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

state(@a) = #12421

Open
p5pRT opened this issue Sep 16, 2012 · 14 comments
Open

state(@a) = #12421

p5pRT opened this issue Sep 16, 2012 · 14 comments

Comments

@p5pRT
Copy link

p5pRT commented Sep 16, 2012

Migrated from rt.perl.org#114932 (status was 'open')

Searchable as RT114932$

@p5pRT
Copy link
Author

p5pRT commented Sep 16, 2012

From @cpansprout

This hasn’t been implemented yet, and I do not see any existing ticket for it.

(state @​a) = ... is not supposed to have the assign-once behaviour.

state(@​a) = ... and state @​a = ... are (if Ι understand correctly).


Flags​:
  category=core
  severity=low


Site configuration information for perl 5.17.4​:

Configured by sprout at Mon Aug 27 23​:00​:20 PDT 2012.

Summary of my perl5 (revision 5 version 17 subversion 4) configuration​:
  Snapshot of​: 22ade07
  Platform​:
  osname=darwin, osvers=10.5.0, archname=darwin-2level
  uname='darwin pint.local 10.5.0 darwin kernel version 10.5.0​: fri nov 5 23​:20​:39 pdt 2010; root​:xnu-1504.9.17~1release_i386 i386 '
  config_args='-de -Dusedevel -DDEBUGGING'
  hint=recommended, useposix=true, d_sigaction=define
  useithreads=undef, usemultiplicity=undef
  useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef
  use64bitint=undef, use64bitall=undef, uselongdouble=undef
  usemymalloc=n, bincompat5005=undef
  Compiler​:
  cc='cc', ccflags ='-fno-common -DPERL_DARWIN -DDEBUGGING -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include',
  optimize='-O3 -g',
  cppflags='-fno-common -DPERL_DARWIN -DDEBUGGING -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include'
  ccversion='', gccversion='4.2.1 (Apple Inc. build 5664)', gccosandvers=''
  intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234
  d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16
  ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
  alignbytes=8, prototype=define
  Linker and Libraries​:
  ld='env MACOSX_DEPLOYMENT_TARGET=10.3 cc', ldflags =' -fstack-protector -L/usr/local/lib'
  libpth=/usr/local/lib /usr/lib
  libs=-ldbm -ldl -lm -lutil -lc
  perllibs=-ldl -lm -lutil -lc
  libc=, so=dylib, useshrplib=false, libperl=libperl.a
  gnulibc_version=''
  Dynamic Linking​:
  dlsrc=dl_dlopen.xs, dlext=bundle, d_dlsymun=undef, ccdlflags=' '
  cccdlflags=' ', lddlflags=' -bundle -undefined dynamic_lookup -L/usr/local/lib -fstack-protector'

Locally applied patches​:
 


@​INC for perl 5.17.4​:
  /usr/local/lib/perl5/site_perl/5.17.4/darwin-2level
  /usr/local/lib/perl5/site_perl/5.17.4
  /usr/local/lib/perl5/5.17.4/darwin-2level
  /usr/local/lib/perl5/5.17.4
  /usr/local/lib/perl5/site_perl
  .


Environment for perl 5.17.4​:
  DYLD_LIBRARY_PATH (unset)
  HOME=/Users/sprout
  LANG=en_US.UTF-8
  LANGUAGE (unset)
  LD_LIBRARY_PATH (unset)
  LOGDIR (unset)
  PATH=/usr/bin​:/bin​:/usr/sbin​:/sbin​:/usr/local/bin​:/usr/X11/bin​:/usr/local/bin
  PERL_BADLANG (unset)
  SHELL=/bin/bash

@p5pRT
Copy link
Author

p5pRT commented Oct 16, 2012

From @cpansprout

On Sun Sep 16 12​:15​:05 2012, sprout wrote​:

This hasn’t been implemented yet, and I do not see any existing ticket
for it.

(state @​a) = ... is not supposed to have the assign-once behaviour.

state(@​a) = ... and state @​a = ... are (if Ι understand correctly).

I believe this reasoning makes sense in Perl 5 (even if it is not
exactly the same as the Perl 6 explanation)​:

It is ‘state’ (with its arguments) that is treated specially on the LHS
of =. So (state @​a)=... is not special-cased, because what is on the
LHS is more than just state. But state(@​a) is special-cased, because
the (@​a) bit is part of the state() call. (Think of state as a function.)

So that means state(our @​foo) = ... should assign to the package
variable @​foo once.

Right?

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Oct 16, 2012

From [Unknown Contact. See original ticket]

On Sun Sep 16 12​:15​:05 2012, sprout wrote​:

This hasn’t been implemented yet, and I do not see any existing ticket
for it.

(state @​a) = ... is not supposed to have the assign-once behaviour.

state(@​a) = ... and state @​a = ... are (if Ι understand correctly).

I believe this reasoning makes sense in Perl 5 (even if it is not
exactly the same as the Perl 6 explanation)​:

It is ‘state’ (with its arguments) that is treated specially on the LHS
of =. So (state @​a)=... is not special-cased, because what is on the
LHS is more than just state. But state(@​a) is special-cased, because
the (@​a) bit is part of the state() call. (Think of state as a function.)

So that means state(our @​foo) = ... should assign to the package
variable @​foo once.

Right?

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Oct 16, 2012

@cpansprout - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Oct 16, 2012

From Eirik-Berg.Hanssen@allverden.no

On Tue, Oct 16, 2012 at 11​:45 PM, Father Chrysostomos via RT <
perlbug-comment@​perl.org> wrote​:

On Sun Sep 16 12​:15​:05 2012, sprout wrote​:

This hasn't been implemented yet, and I do not see any existing ticket
for it.

(state @​a) = ... is not supposed to have the assign-once behaviour.

state(@​a) = ... and state @​a = ... are (if Ι understand correctly).

I believe this reasoning makes sense in Perl 5 (even if it is not
exactly the same as the Perl 6 explanation)​:

It is 'state' (with its arguments) that is treated specially on the LHS
of =. So (state @​a)=... is not special-cased, because what is on the
LHS is more than just state. But state(@​a) is special-cased, because
the (@​a) bit is part of the state() call. (Think of state as a function.)

So that means state(our @​foo) = ... should assign to the package
variable @​foo once.

Right?

  ... and evaluate the RHS only once (as in the scalar case). Oh, and as
I was reminded recently, that's "once per subref" - as in the scalar case​:

eirik@​bluebird[00​:31​:09]$ perl -E 'for (1..2) { sub {
eirik@​bluebird[00​:31​:09]
$
perl -E 'for (1..2) { sub { for (1..3) { state $t=warn; say } }->() }'
Warning​: something's wrong at -e line 1.
1
2
3
Warning​: something's wrong at -e line 1.
1
2
3
eirik@​bluebird[00​:31​:11]~$

  I think "evaluate the RHS only once" means that the RHS is _also_ part of
the state call, but other than that, I think you got it. Or at least, I
agree. :)

Eirik

@p5pRT
Copy link
Author

p5pRT commented Oct 17, 2012

From @ap

* Father Chrysostomos via RT <perlbug-comment@​perl.org> [2012-10-16 23​:50]​:

So that means state(our @​foo) = ... should assign to the package
variable @​foo once.

Right?

  $ perl -E'my (our $foo) = 1; say $​::foo ? 1 : 0'
  1
  $ perl -E'our (my $foo) = 1; say $​::foo ? 1 : 0'
  0

To my mind that is a “no”. So far `state` is basically just another
declarator, which in Perl can be strewn throughout an expression, and
the closest declarator wins. But it’s already not quite just another
declarator, but one with some special behaviour. That’s fine but I don’t
think I want its semantics complicated further so that it becomes kind
of a declarator with some special behaviour that also modifies some
other declarators within the expression.

(Maybe it is a missed opportunity that isn’t spelled `state my`. I care
not to tug that ship back into the port now by the anchor line though.)

For those times where you really need this functionality you might be
able to just abuse lexical `state`​:

  { state $init = do { our $foo = 1 } }

Not as obvious as I would like, but at least not ugly either.

And with the aid of Devel​::CallSite you can sugar it up to the point of

  stately { our $foo = 1 };

--
*AUTOLOAD=*_;sub _{s/​::([^​:]*)$/print$1,(",$\/"," ")[defined wantarray]/e;chop;$_}
&Just->another->Perl->hack;
#Aristotle Pagaltzis // <http​://plasmasturm.org/>

@p5pRT
Copy link
Author

p5pRT commented Oct 17, 2012

From @cpansprout

On Tue Oct 16 17​:31​:22 2012, aristotle wrote​:

* Father Chrysostomos via RT <perlbug-comment@​perl.org> [2012-10-16
23​:50]​:

So that means state(our @​foo) = ... should assign to the package
variable @​foo once.

Right?

$ perl \-E'my \(our $foo\) = 1; say $&#8203;::foo ? 1 : 0'
1
$ perl \-E'our \(my $foo\) = 1; say $&#8203;::foo ? 1 : 0'
0

To my mind that is a “no”. So far `state` is basically just another
declarator, which in Perl can be strewn throughout an expression, and
the closest declarator wins. But it’s already not quite just another
declarator, but one with some special behaviour. That’s fine but I don’t
think I want its semantics complicated further so that it becomes kind
of a declarator with some special behaviour that also modifies some
other declarators within the expression.

(Maybe it is a missed opportunity that isn’t spelled `state my`.

But then would return \state my $x give the same variable each time?
(I.e., I don’t consider it a lost opportunity, as state is yet another
scope, different from my and our.)

I care
not to tug that ship back into the port now by the anchor line though.)

For those times where you really need this functionality you might be
able to just abuse lexical `state`​:

\{ state $init = do \{ our $foo = 1 \} \}

Not as obvious as I would like, but at least not ugly either.

My question is more ‘Where do we draw the line?’ than ‘Isn’t this useful?’

Where do *you* think we should draw the line between state controlling
the rhs of assignment and state not controlling the rhs of assignment?
And will it involve more than one special case?

What I like about my explanation above between the difference between
(state @​a) and state(@​a) is that it can be said simply with no
qualifications​: = is special if the left-hand operand is state(...).

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Oct 17, 2012

From [Unknown Contact. See original ticket]

On Tue Oct 16 17​:31​:22 2012, aristotle wrote​:

* Father Chrysostomos via RT <perlbug-comment@​perl.org> [2012-10-16
23​:50]​:

So that means state(our @​foo) = ... should assign to the package
variable @​foo once.

Right?

$ perl \-E'my \(our $foo\) = 1; say $&#8203;::foo ? 1 : 0'
1
$ perl \-E'our \(my $foo\) = 1; say $&#8203;::foo ? 1 : 0'
0

To my mind that is a “no”. So far `state` is basically just another
declarator, which in Perl can be strewn throughout an expression, and
the closest declarator wins. But it’s already not quite just another
declarator, but one with some special behaviour. That’s fine but I don’t
think I want its semantics complicated further so that it becomes kind
of a declarator with some special behaviour that also modifies some
other declarators within the expression.

(Maybe it is a missed opportunity that isn’t spelled `state my`.

But then would return \state my $x give the same variable each time?
(I.e., I don’t consider it a lost opportunity, as state is yet another
scope, different from my and our.)

I care
not to tug that ship back into the port now by the anchor line though.)

For those times where you really need this functionality you might be
able to just abuse lexical `state`​:

\{ state $init = do \{ our $foo = 1 \} \}

Not as obvious as I would like, but at least not ugly either.

My question is more ‘Where do we draw the line?’ than ‘Isn’t this useful?’

Where do *you* think we should draw the line between state controlling
the rhs of assignment and state not controlling the rhs of assignment?
And will it involve more than one special case?

What I like about my explanation above between the difference between
(state @​a) and state(@​a) is that it can be said simply with no
qualifications​: = is special if the left-hand operand is state(...).

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Sep 24, 2013

From @ap

* Father Chrysostomos <perlbug-comment@​perl.org> [2012-10-17 03​:00]​:

* Aristotle Pagaltzis <pagaltzis@​gmx.de> [2012-10-17 02​:35]​:

$ perl \-E'my \(our $foo\) = 1; say $&#8203;::foo ? 1 : 0'
1
$ perl \-E'our \(my $foo\) = 1; say $&#8203;::foo ? 1 : 0'
0

To my mind that is a “no”. So far `state` is basically just another
declarator, which in Perl can be strewn throughout an expression,
and the closest declarator wins. But it’s already not quite just
another declarator, but one with some special behaviour. That’s fine
but I don’t think I want its semantics complicated further so that
it becomes kind of a declarator with some special behaviour that
also modifies some other declarators within the expression. (Maybe
it is a missed opportunity that isn’t spelled `state my`.

But then would return \state my $x give the same variable each time?
(I.e., I don’t consider it a lost opportunity, as state is yet another
scope, different from my and our.)

My impulse was to contradict this until I finally realised I’m wrong.

I felt that `my` and `our` are about visibility, while `state` is the
exact same in terms of visibility as `my` is, except it also concerns
temporal scoping. But then I couldn’t really explain away `our`. In the
end I realised they *all* provide lexical visibility, and the difference
is just in the object that the variable they are giving visibility to is
attached to – with the consequential lifetime of that variable and thus
its temporal scoping.

So I withdraw that argument, and thanks for helping me clear my thoughts
on this.

Though on the converse, this only strengthens my argument that `state`
is just another declarator and therefore shouldn’t go around imposing
its rules onto variables already declared by other declarators.

I care not to tug that ship back into the port now by the anchor
line though.)

For those times where you really need this functionality you might
be able to just abuse lexical `state`​:

\{ state $init = do \{ our $foo = 1 \} \}

Not as obvious as I would like, but at least not ugly either.

My question is more ‘Where do we draw the line?’ than ‘Isn’t this
useful?’

Where do *you* think we should draw the line between state controlling
the rhs of assignment and state not controlling the rhs of assignment?
And will it involve more than one special case?

What I like about my explanation above between the difference between
(state @​a) and state(@​a) is that it can be said simply with no
qualifications​: = is special if the left-hand operand is state(...).

That *is* attractive, but I don’t know if it’s really a good idea.

Consider the status quo here​:

  $ perl -E 'sub x { state(my $x) = "a"; $x++ // "(undef)" }; say x; x; say x'
  a
  a
  $ perl -E 'sub x { state( $x) = "a"; $x++ // "(undef)" }; say x; x; say x'
  a
  c

How (else?) should that work? And why? If `state` is just another kind
of scope like `my`, and in this case `my` has already won, then `$x` is
a lexical variable. What would you intend to do differently here?

If I take your proposal at face value, it would become this​:

  $ perl -E 'sub x { state(my $x) = "a"; $x++ // "(undef)" }; say x; x; say x'
  a
  (undef)

I.e. the upshot of your proposal would be that assignment to a `state`
operation has *its own* tied-to-the-function execution scope separate
from that of the variable being declared within the `state` expression,
if any.

I don’t think I like having `state` be two different things.

Also, currently this is an error​:

  $ perl -E 'sub x { my(state $x) = "a"; $x++ // "(undef)" }; say x; x; say x'
  Initialization of state variables in list context currently forbidden at -e line 1, near ""a";"
  Execution of -e aborted due to compilation errors.

What would you want this to do?

What would you want *this* to do if list assignment were no longer
forbidden?

  $ perl -E 'sub x { state($x, my $y) = ("a", "b"); $x++ // "(undef)" }; say x; x; say x'

Does this assign "a" to $x only once but "b" to $y every time? If not,
do you give $y the state variable treatment or $x the non-state variable
treatment?

The way I understand it you’d give $y the state variable treatment here,
but is it a good idea for a `state(...)=...;` statement to have special
scope, overloading what `state` as an expression does?

Note that if we decide that you will never be able to mention more than
one variable to `state` (even if that is a container), and it’s not just
something we left out “for now”, then we *can* come up with consistent
semantics – and we can go with very nearly your formulation of the rule​:
“assignment is special if the left-hand operand is `state` declaring
a new state variable”. Not entirely free of qualifications as you’d’ve
liked it, but seems close enough to me. Since only a single variable can
be given to `state` at a time, we avoid having to deal with the case of
assigning a list to a mixed-scopes list of variables, and therefore
avoid potentially having to think of `state` in an assignment as being
scoped as-an-operation separately from the variables involved on the LHS
of that assignment.

That would then imply the following​:

  $ perl -E 'sub x { my(state $x) = "a"; $x++ // "(undef)" }; say x; x; say x'
  a
  a

This is not terrible. It would also imply that the state($x, my $y)
example will never work, with any semantics, which I’m fine with.

I’m not happy.

Any which way I turn it, this is messy, with no apparent way to handle
it gracefully. The only solution appears to be to outlaw the messy cases
rather than admit them.

Regards,
--
Aristotle Pagaltzis // <http​://plasmasturm.org/>

@p5pRT
Copy link
Author

p5pRT commented Aug 20, 2016

From @rjbs

A lot of the discussion on this ticket was about the behavior of state(our...) or state(my...)

This problem has been designed away by v5.24, in which nested declarators are illegal.

I'm writing a fair bit of code targeting v5.24 right now, and I've found that there are many cases where I would really like to use "state @​arr = ...;"

Since the concerns of this ticket *seem* to be gone, now, can we press forward?

--
rjbs

@p5pRT
Copy link
Author

p5pRT commented Nov 3, 2017

From zefram@fysh.org

Amusingly, the present prohibition on list initialisation of state
variables doesn't detect sufficiently convoluted lists. For example,

$ perl -Mfeature=state -lwe 'my $i = 0; sub f { (state ($a, $b), undef) = ($i++, "z"); print $a, $b; } f(); f(); print $i'
0z
1z
2

whereas either of those pairs of parens in the absence of the other is
detected as an illegal list initialisation​:

$ perl -Mfeature=state -lwe 'my $i = 0; sub f { state ($a, $b) = ($i++, "z"); print $a, $b; } f(); f(); print $i'
Initialization of state variables in list context currently forbidden at -e line 1, near ");"
Initialization of state variables in list context currently forbidden at -e line 1, near ");"
Execution of -e aborted due to compilation errors.
$ perl -Mfeature=state -lwe 'my $i = 0; sub f { (state $a, undef) = ($i++, "z"); print $a; } f(); f(); print $i'
Initialization of state variables in list context currently forbidden at -e line 1, near ");"
Execution of -e aborted due to compilation errors.

Fortunately, the consensus semantics that we started out aiming for,
and which no one has yet argued against, give the accidentally-permitted
lists the same behaviour that they accidentally have. So we can probably
just roll with that.

Anyway, using the flags that are already available in ops is not quite
enough to make the distinctions that this ticket calls for. We can, for
example, distinguish "state @​a" from "(state @​a)", in order to make the
former legal. But "state(@​a)" and "(state @​a)" have identical flags,
so it's not straightforward to give them the different behaviour that
we want. But "state @​a :shared", "state (@​a) :shared", "(state @​a
:shared)", and "(state (@​a) :shared)" are all distinct.

As a first step, I think we should allow unparenthesised "state @​a"
for initialisation. This gets us the most important functionality, of
being able to initialise an array or hash state variable. We'd leave
other types of list assignment forbidden in this first stage. I was
thinking about how to consistently forbid only constructions with parens
on the lhs, which was how I ran into the inconsistency described above.
Wanting to keep legal the things that are currently accidentally legal,
and not change their behaviour, complicates this a bit.

Without going beyond the clues offered by the existing flags, we could
also chip some legal non-initialisation assignments out of the other side
of the currently-forbidden territory. But ultimately it's going to take
a real parsing tweak to distinguish between "state(@​a)" and "(state @​a)".

-zefram

@p5pRT
Copy link
Author

p5pRT commented Nov 4, 2017

From zefram@fysh.org

I wrote​:

As a first step, I think we should allow unparenthesised "state @​a"
for initialisation.

Over the last couple of days I've gone back and forth on whether it's
sensible to do more than just that in the first stage. With the case of
"state @​a :attr" to consider, the code to detect the unparenthesised case
would be quite complicated and have some overlap with the existing code
to detect forbidden list-mode initialisation. So I started writing some
more integrated code that would handle all possible cases in one go.
But then I realised there were way more cases than I'd thought about,
started cataloguing them, found a couple of mishandled cases, and
eventually came to the conclusion that we couldn't make useful inroads
into the currently forbidden cases beyond the unparenthesised cases.
So back to detecting just that.

Code to permit initialisation of unparenthesised variables is now in blead
as commit f99042c. This comes with
a significant expansion of the set of forbidden cases that are tested
for, based on the range of cases I've catalogued. This is a practical
necessity in order to make sure the detection of the newly-permitted
case is sufficiently narrow.

Rather than permit a handful more scenarios under the current op flag
arrangements, I reckon the sensible next step is to add the new flag
stuff that will ultimately be required to make all the distinctions that
we want. It would also make sense to fix the mishandled cases that I
found ([perl #132393] and [perl #132394]) before opening up the currently
forbidden space. The mishandled cases might require a deprecation cycle.

-zefram

@p5pRT
Copy link
Author

p5pRT commented Nov 12, 2017

From @xsawyerx

On 11/04/2017 11​:03 PM, Zefram wrote​:

I wrote​:

As a first step, I think we should allow unparenthesised "state @​a"
for initialisation.
Over the last couple of days I've gone back and forth on whether it's
sensible to do more than just that in the first stage. With the case of
"state @​a :attr" to consider, the code to detect the unparenthesised case
would be quite complicated and have some overlap with the existing code
to detect forbidden list-mode initialisation. So I started writing some
more integrated code that would handle all possible cases in one go.
But then I realised there were way more cases than I'd thought about,
started cataloguing them, found a couple of mishandled cases, and
eventually came to the conclusion that we couldn't make useful inroads
into the currently forbidden cases beyond the unparenthesised cases.
So back to detecting just that.

But do we need to?

Considering nested declarations are not allowed, when is distinguishing
between "(state @​x)=" and "state(@​x)=" important? The original concerns
related to that, did they not?

Code to permit initialisation of unparenthesised variables is now in blead
as commit f99042c. This comes with
a significant expansion of the set of forbidden cases that are tested
for, based on the range of cases I've catalogued. This is a practical
necessity in order to make sure the detection of the newly-permitted
case is sufficiently narrow.

This is great.

This basically now supports "state @​x=" but not yet "state(@​x)=" because
it cannot be distinguished from "(state @​x)=". (This is a note to self,
I suppose.)

@p5pRT
Copy link
Author

p5pRT commented Nov 12, 2017

From zefram@fysh.org

Sawyer X wrote​:

                                            when is distinguishing

between "(state @​x)=" and "state(@​x)=" important?

It's important because, under the principles we favour, they would have
different behaviour. The former is an unconditional assignment, whereas
the latter is a state variable initialisation. This arises because the
favoured rule is concerned with whether the syntactic top level of the
lhs is a state declaration. In order to not need to distinguish between
them, we'd need to have some other rule for deciding which syntactic
assignments are actually state variable initialisations.

This whole fuss arises from the rather dubious design decisions that
(a) state initialisation should look like unconditional assignment
and (b) state variable declarations should be ordinary expressions.
We could have avoided the whole fuss by saying that "state (...) =
..." is statement syntax, with "(state @​x)" being illegal anywhere.
But we had the precedent of "my".

-zefram

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

No branches or pull requests

2 participants