develooper Front page | perl.perl5.porters | Postings from April 2012

Re: [perl #24250] "return" required in some anonymous closures

From:
Dave Mitchell
Date:
April 20, 2012 08:55
Subject:
Re: [perl #24250] "return" required in some anonymous closures
Message ID:
20120420155512.GC2881@iabyn.com
On Fri, Apr 20, 2012 at 12:37:55PM +0100, Nicholas Clark wrote:
> constant.pm now takes advantage of the "proxy constant subroutines"
> on all versions from 5.10.0 onwards. It no longer users the fragile
> "feature" under discussion here, that
> 
>     *foo::bar = sub () { $baz; }

Well, having a quick look at constant.pm, it may use the new method as its
primary route, buts there's still plenly of places where it uses the old
mechanism, even down to

    my $const = $] > 5.009002;
    *_CAN_PCS = sub () {$const};

[ just by-the-by, I don't understand why constant.pm is written in such a
way as to be able to run under old perls; its not as if its a dual-life
CPAN distribution ]

I don't know enough about how the new method works to be abloe to say
whether it can be rewritten to avoid sub(){$x} completely, or whether
we need to add some sort of XS mechanism for the general case.

> So, do we want to remove the inlining of (inferred to be)-constant value
> closures? And only inline subroutines that trivially return true constants.
> And fix this 5.8.0 regression. What is relying on the regressed behaviour?
> 
> In the general case, is it impossible to detect all scenarios where the
> variable within the closure can not later be modified?

It's effectively impossible, and its trivially easy to later modify the
variable.
For example under 5.8.0, where the refcnt < 2 test was done at compile
time, the 1st sub would see a refcnt of 1 and mark the sub as 'convert to
const when cloning at time', then compiling the second sub retractively
allows you to modify the var:

    {
	my $x = ...;
	sub () {$x};      # at compile time, has refcnt==1, looks safe...
	sub bad { $x++ }; # ..but it isn't
    }

After I changed it so that the refcnt < 2 test is done at runtime during
cloning, that can be defeated with

    {
	my $x = ...;
	sub () {$x};     # at runtime, has refcnt==1, looks safe...
	$::global = \$x; # now has a refcnt of 2, so isn't safe
    }

So, I think we should remove this 'feature'.
If anyone is using it as intended, then the worst they'll get is
a performance decrease, with a const sub downgraded to a real sub that
returns the expected value. Perhaps we could issue a warning, with
perldiag.pod explaining what to do if you really wanted a const sub, and
to stick a 'return' in to defeat the warning if you didn't want it.

-- 
Dave's first rule of Opera:
If something needs saying, say it: don't warble it.



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