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

Re: Is it time to separate pad names from SVs?

Thread Previous | Thread Next
From:
=?UTF-8?B?w4Z2YXIgQXJuZmrDtnLDsCBCamFybWFzb24=?=
Date:
November 1, 2014 06:18
Subject:
Re: Is it time to separate pad names from SVs?
Message ID:
CACBZZX5FKu6Gc-P-0vFZShupV3Oj9EjhtwipzqY9qiaVgxew9Q@mail.gmail.com
On Sat, Nov 1, 2014 at 12:41 AM, Father Chrysostomos <sprout@cpan.org> wrote:
> Avar wrote:
>> Since then we've said this in our docs:
>>
>>     If the result after optimization and constant folding is either a
>>     constant or a lexically-scoped scalar which has no other references,
>>     then it will be used in place of function calls made without C<&>
>>
>>     -- http://perldoc.perl.org/perlsub.html#Constant-Functions
>
> It says 'after optimization', but some of the checks actually hap-
> pen before optimization finishes, so it doesn't currently work as
> documented.
>
> We also document that adding an explicit 'return' changes the behav-
> iour, but after optimisation there is no return left in the execution
> chain if it was at the end of the sub.
>
>> Which to me means that when the parser sees "sub () { $x }" *all* it
>> checks is whether that $x has one reference, and if it does whatever
>> value it has is inlined, no exceptions. While we *probably* wouldn't
>> break much if we changed the behavior of these cases you're mentioning
>> here we'd explicitly be changing already documented behavior.
>
> But what exactly does 'reference' mean?  Mentioning the variable in
> the source code is a way of referencing.  Referencing the variable
> does not have to be linked to the internal SvREFCNT.
>
> And what about state variables?  What about lvalue subs?  What about
> custom attributes?
>
>> Personally I don't think this is worth changing.
>
> Should we then remove the 'Yes, this is ugly, and should be killed'
> comment from pad.c?
>
>> We've documented that
>> this works a certain way for a *long* time, and there's a trivial
>> workaround to make all these cases you mention work which has also
>> been documented for an equally long time. Just make the body of the
>> function include something else than a single scalar.
>
> I would appreciate it if you could respond to bug #123092.

I see after looking at this an some of your other posts here a bit
closer that there's bigger gains to be had by poking this particular
hornet's nest than I initially thought.

A lot of the stuff surrounding this is quite hairy, e.g. the warning
case in #121841, and as you mention in #123092 some aspects of this
never really worked as advertised.

There's also the question of what promises we should be making about
constant subs, those essentially fall into two categories. Those users
who are expecting them to result in performance advantages, and those
who may be relying on some edge cases of the implementation (e.g.
being able to change $x after it's inlined).

I'm in the former category, I have some code that very heavily relies
on the performance advantages of being able to fold out certain blocks
at compile-time, and it was only by pure dumb luck that I noticed that
your previous fix broke the *very* common use-case of just doing "sub
() { $x }" before it made it into a production release. I've seen a
lot of code in the wild that uses that well-known feature to create
constant subs, I've never seen anyone attempt to use it to implement
the cases you want to support. I realize that's anecdotal, but I've
been writing Perl for a while now.

I initially chased that bug in your initial patch down because it
broke Constant::Export::Lazy, a constant defining module I wrote that
promises to create inline-able subroutines.

https://metacpan.org/source/AVAR/Constant-Export-Lazy-0.08/lib/Constant/Export/Lazy.pm#L351

I notice now that that code, written explicitly to try to carefully
define constant subs could easily run afoul of a fix of yours and
suddenly start creating non-constant subroutines. After I inline a
"sub () { $value }" I pass the $value to another function (which can
validate or log it or whatever). That function would be free to change
the value, so if we were to make inline-able subroutines work like
"normal" subroutines that code wouldn't be creating inline-able
subroutines anymore. It's essentially doing something like this:

    $ perl -E 'sub after { my $cp = \$_[0]; $$cp = 2 } my $value = 1;
*HELLO = sub () { $value }; after($value); say HELLO(); say $value'
    1
    2

I think that any attempt to make the special case that is constant
subroutines behave more like "normal" perl code is bound to either
fail, or make defining constant subroutines a very fickle affair. You
wouldn't even be able to print out the value you just defined because
someone might have overridden the print sub to change $_[0].

I think the only sane thing to do is to bless the currently documented
method of doing this, which is that when you do "*CONST = sub () { $x
}" we read the *current* value of $x and inline that, no matter what
happens to $x after that.

I think it would also be very nice to expand that particular feature,
so you could e.g. do "*CONST = sub () : const { if ($x) { return $y }
else { return $z } }" and have it run and inline that when it's
defined.

What I don't think is nice is to retroactively change code in the wild
that's obviously expecting this to work one way to work another way,
without having some deprecation cycle.

I don't think that it's a bad idea to e.g. warn about ambiguous uses
of variables surrounding constant subroutines.

Thread Previous | 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