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

Flipflop under recursion #14110

Closed
p5pRT opened this issue Sep 23, 2014 · 9 comments
Closed

Flipflop under recursion #14110

p5pRT opened this issue Sep 23, 2014 · 9 comments

Comments

@p5pRT
Copy link

p5pRT commented Sep 23, 2014

Migrated from rt.perl.org#122829 (status was 'resolved')

Searchable as RT122829$

@p5pRT
Copy link
Author

p5pRT commented Sep 23, 2014

From @cpansprout

perlop.pod states​:

  Each ".." operator
  maintains its own boolean state, even across calls to a subroutine
  that contains it.

While that is true and well-known, what few know is that recursive calls to the containing subroutine do not share that boolean state with the outer call. What’s weirder is that each recursion level maintains its own state. So, for instance, if you have a function calling itself recursively to the fifth level, the flip-flop operator evaluated at that level will not use the same state again until that function is called to that level again.

I haven’t come up with an example of this weird behaviour yet, but I’ll try to post something in the next day or two.

My question is​: Is this behaviour intentional? It doesn’t match my reading of the documentation. And I can’t think of any use for it short of obfuscation. I am inclined to think this is a bug.

Further, I have found a discrepancy in this operator, in that it returns the same scalar each time when the enclosing sub is not called recursively, but a different scalar each time when the enclosing sub *is* called recursively.

I was about to fix that discrepancy, when I realised that sharing the state between recursion levels would make the fix easier (the same change would fix both).

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Sep 23, 2014

From @jandubois

On Mon, Sep 22, 2014 at 6​:13 PM, Father Chrysostomos
<perlbug-followup@​perl.org> wrote​:

I was about to fix that discrepancy, when I realised that sharing the state between recursion levels would make the fix easier (the same change would fix both).

I don't actually know how this works, but I assume the observed
behavior is due to the state being kept in the pad. Does your fix for
sharing the state still work for threaded interpreters, where each
interpreter needs to keep separate state? So just hanging it of the
opcode wouldn't work.

Cheers,
-Jan

@p5pRT
Copy link
Author

p5pRT commented Sep 23, 2014

The RT System itself - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Sep 23, 2014

From @cpansprout

On Mon Sep 22 18​:19​:26 2014, jdb wrote​:

On Mon, Sep 22, 2014 at 6​:13 PM, Father Chrysostomos
<perlbug-followup@​perl.org> wrote​:

I was about to fix that discrepancy, when I realised that sharing the
state between recursion levels would make the fix easier (the same
change would fix both).

I don't actually know how this works, but I assume the observed
behavior is due to the state being kept in the pad.

Your assumption is correct.

Does your fix for
sharing the state still work for threaded interpreters, where each
interpreter needs to keep separate state? So just hanging it of the
opcode wouldn't work.

I was thinking of having the same SV in the recursive pads, just as we do for constants under threads.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Sep 23, 2014

From @cpansprout

On Mon Sep 22 18​:26​:08 2014, sprout wrote​:

On Mon Sep 22 18​:19​:26 2014, jdb wrote​:

On Mon, Sep 22, 2014 at 6​:13 PM, Father Chrysostomos
<perlbug-followup@​perl.org> wrote​:

I was about to fix that discrepancy, when I realised that sharing
the
state between recursion levels would make the fix easier (the same
change would fix both).

I don't actually know how this works, but I assume the observed
behavior is due to the state being kept in the pad.

Your assumption is correct.

Does your fix for
sharing the state still work for threaded interpreters, where each
interpreter needs to keep separate state? So just hanging it of the
opcode wouldn't work.

I was thinking of having the same SV in the recursive pads, just as we
do for constants under threads.

And by making the pad code treat them like constants, I thought I could avoid special cases. But that would cause closures to share state, whereas currently they don’t, and that could have serious consequences for backward-compatibility.

So it looks as though I have to special-case flip targets regardless.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Sep 23, 2014

From @cpansprout

On Mon Sep 22 18​:13​:16 2014, sprout wrote​:

Further, I have found a discrepancy in this operator, in that it
returns the same scalar each time when the enclosing sub is not called
recursively, but a different scalar each time when the enclosing sub
*is* called recursively.

I was about to fix that discrepancy, when I realised that sharing the
state between recursion levels would make the fix easier (the same
change would fix both).

I went ahead and fixed that discrepancy in commit 14d9114 without touching the recursion issue.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Oct 28, 2014

From @cpansprout

On Mon Sep 22 18​:13​:16 2014, sprout wrote​:

perlop.pod states​:

Each ".." operator
maintains its own boolean state, even across calls to a subroutine
that contains it.

While that is true and well-known, what few know is that recursive
calls to the containing subroutine do not share that boolean state
with the outer call. What’s weirder is that each recursion level
maintains its own state. So, for instance, if you have a function
calling itself recursively to the fifth level, the flip-flop operator
evaluated at that level will not use the same state again until that
function is called to that level again.

I haven’t come up with an example of this weird behaviour yet, but
I’ll try to post something in the next day or two.

s/day/month/ :-)

# This routine maintains multiple flip-flop states, each with its own
# numeric ID, starting from 1. Pass the ID as the argument.
sub f {
  my $depth = shift() - 1;
  return f($depth) if $depth;
  return /3/../5/;
}

for(1..20) {
  if (f(1)) {
  my $outer = $_;
  for(1..10){
  print "$outer $_\n" if f(2);
  }
  }
}

The output is​:

3 3
3 4
3 5
4 3
4 4
4 5
5 3
5 4
5 5
13 3
13 4
13 5
14 3
14 4
14 5
15 3
15 4
15 5

Now how much code is depending on that bug? None, I would imagine. And if someone wanted to write something like the above, an array of closures would be a more straightforward way to do it. After all, the higher the ID, the slower the flip-flop function.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Oct 29, 2014

From @cpansprout

On Mon Sep 22 18​:13​:16 2014, sprout wrote​:

perlop.pod states​:

Each ".." operator
maintains its own boolean state, even across calls to a subroutine
that contains it.

While that is true and well-known, what few know is that recursive
calls to the containing subroutine do not share that boolean state
with the outer call. What’s weirder is that each recursion level
maintains its own state. So, for instance, if you have a function
calling itself recursively to the fifth level, the flip-flop operator
evaluated at that level will not use the same state again until that
function is called to that level again.

Fixed in 00e4076.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Oct 29, 2014

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

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

1 participant