develooper Front page | perl.perl5.porters | Postings from October 2014

RVs in pads; lvalue references

Thread Next
From:
Father Chrysostomos
Date:
October 8, 2014 20:14
Subject:
RVs in pads; lvalue references
Message ID:
20141008201423.29158.qmail@lists-nntp.develooper.com
The short version:

state and foreach do not mix.  The same bug also makes

    my $a; eval'\$a=\$b'

do nothing.  (I am working on lvalue references right now.)  Is it
acceptable to introduce experimental lvalue references with that
drawback?  The rest of the message discusses ways to fix the bug.

The long version:

use 5.01;
sub f {
  state $x;
  $x = 42 if !caller(1);
  if (!@_) { return }
  my $what = shift;
  if ($what eq 'print x2') { # print $x under recursion (depth=2)
    f('print x');
  }
  elsif ($what eq 'print x') {
    print "$x\n";
  }
  elsif ($what eq 'alias') {
    foreach $x (100) {
      f();
    }
  }
}
#f('print x2');
f('alias');
f('print x2');

This script outputs 100, because in the 2nd call depth $x is perma-
nently bound to the 100 constant that it was temporarily aliased to by
the foreach loop in the first f() call.

If we uncomment the line that is commented out, we get 42 twice.  This
is because $x is now correctly shared between the two depths.

This exposes a bug in the way that closures are handled.  (This exam-
ple is not a closure example, but closure would exhibit the same bug
as the principle is the same: multiple pads point to the same SV, but
aliasing only affects one pad at a time.)

One way to fix this would be to put RVs in pads instead of putting
values in the pads directly.

While I don't think it would slow things down considerably, the
slowdown would probably be measurable, and I would have a lynch
mob after me.  (Slowing down lexical variables is sacrilege. :-)

Another approach I thought of was to store a generation number some-
where (e.g., the pad name) and have padxv ops that are flagged as
closing over outer subs fetch the new value if the current value is
stale.  But storing the generation number in the pad name is compli-
cated, as I made CV clones share pad names about two years ago, for
efficiency.  And then it is complicated to find the outer sub, as clo-
sures no longer point to it as of about two years ago, again, for
efficiency.  (So much for efficiency!)

So I'm not sure how to proceed.  Maybe we just need to use RVs (and
actually benchmark them to see how much slowdown we get).  Maybe we
should only use RVs if the current sub or an inner sub contains evals.
(Getting that to work would be hard.)  Maybe we need a lightweight
reference-counted SV pointer, which we would call a PADSLOT, since the
SV head is 8-12 bytes bigger than we need.  But I loathe breaking all
the CPAN modules that handle pads directly via PadARRAY.  (The whole
point of the new pad API was to avoid future breakage.)

I would appreciate any bright ideas.

If we can't fix this now, is it acceptable to introduced experimen-
tal lvalue references with this drawback?  my $a; eval { \$a = \$b }
would be ineffective, as the aliasing would only take place in the
eval's own pad.


Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About