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

Remove Devel::BeginLift #51

Merged
merged 13 commits into from Nov 8, 2012
Merged

Remove Devel::BeginLift #51

merged 13 commits into from Nov 8, 2012

Conversation

schwern
Copy link
Contributor

@schwern schwern commented Aug 16, 2012

This patch series eliminates Devel::BeginLift per #39.

Instead of using BeginLift it simply rewrites "method foo {...}" as "method &foo; sub foo { ... }".

Tested with Strawberry Perl 5.16.1 64 bit. That's what I have on my VM. Needs more Windows testing, but it can't be any worse than the shape we're currently in.

…Lift.

Rather than using Devel::BeginLift or declaring things with a BEGIN block,
we simply rewrite "func foo {...}" to be "sub foo {...}" and the rest
happens magically.

The one caveat is Devel::Declare expects `func` and `method` to get
the code ref being generated.  Rather than fight this, we go along
with it.

Only four tests fail.  Fixes on the way.
Devel::Declare::MethodInstaller::Simple will add "sub $attrs" to
$before in inject_if_block() if it sees attributes.  This messes with
our custom inject_if_block().  So just ignore anything already on
$before and handle attributes ourselves.
Method::Signatures::Modifiers always defines methods at runtime.  It
was doing this by overriding code_for(), but the compile time logic
has moved.  Overriding _do_compile_at_BEGIN() is safer.
Check that the resulting list is what we expect it to be.
Otherwise func() might swallow everything in the list.
This was necessary when we were doing more complicated things to
work around Devel::BeginLift.  Now its just a copy of the one
from Devel::Declare::Context::Simple.
For some odd reason I don't understand, Devel::Declare only wants you to
inject "sub" for named routines.  Anon routines don't get a sub nor
do they need to pass attributes.  *shrug*
@barefootcoder
Copy link
Contributor

Okay, I've had a chance to go over the code more closely now. Here are the comments I have:

  • The comment for inject_if_block says: For instance, if it's an anonymous sub, the $before parameter would contain "sub ". (And, yes, I know you didn't write that--I did. But that may have been due to an incomplete understanding on my part.) But the parser from Devel::Declare::MethodInstaller::Simple seems to determine whether or not to provide a $before argument not based on whether or not the sub is anonymous, but rather whether or not it has attributes. Now, I'm not entirely sure why this is, but would it matter at all to the way you've implemented inject_if_block in MS?
  • You're ignoring (effectively throwing away) the $before argument for all named subs. Particularly in the case of MSM, which is slapping in a 'sub ' in all cases, throwing away $before seems bad. Of course, I'm starting to suspect that MSM's inject_if_block is no longer necessary with the code you've got here--I'm going to test that on a few different versions of Perl before I change it though--so perhaps that's moot. But there's still parser from DDMIS, which will set $before in the presence of attributes. I suppose you're getting around that by setting the attributes yourself via $self->{attributes}, but still ... this seems like one of those things that may conveniently work today, but may give us troubles tomorrow if someone changes something upstream ... or maybe downstream, if someone overrides something and passes us a $before that we then toss. Not entirely sure what the right answer here is, but I wanted to throw it out there so we were aware of it.

And I think that's all I can see that needs your counter-comment. As I say, next I will set up a little perlbrew farm and test this on some different Perl versions. If that all looks good, I'm going to play around with removing the inject_if_block from MSM (it almost surely is redundant at this point). And if that looks good, and you have no worries from my comments above, I'll just go ahead and merge the branch, turn it into a dev version, and set CPAN Testers on it.

Thoughts?

Conflicts:
	lib/Method/Signatures.pm
Buddy also thought the way anonymous functions with attributes were handled
is fishy.  Figured out why Devel::Declare::MethodInstaller::Simple->parser
will only add the "sub" for attributes.  It has to do with a quirk in how
prototypes are parsed.  Here's two versions of what a compiled anon
func might look like.

  # If we leave out the "sub".
  sub func(&) { return shift; };
  my $a = [ func { 123 }, 1 ];

  # If we always put in a "sub".
  sub func(&) { return shift; };
  my $a = [ func sub { 123 }, 1 ];

The top one works, the bottom one fails "too many arguments for
main::func".  The prototype must be getting confused.  This may be why
it fixed a 5.10 bug, there may have been a prototype glitch.  Or maybe
this behavior is a prototype glitch.  Either way it works now on
5.10.0 and 5.14.1.

The t/larna.t tests catch this problem.

There's no need to replicate the Devel::Declare logic, only in the
case of a BEGIN lift.  I can no longer replicate a 5.10 bug.  It's
possible the bug was tickled by Devel::BeginLift.

Signed-off-by: Michael G. Schwern <schwern@pobox.com>
@schwern
Copy link
Contributor Author

schwern commented Oct 27, 2012

Sorry I dropped off the Internet for a while.

I was confused about how that works, too, but I just figured it out and found
a bug. Take this...

my $foo = func { ... };

it compiles into something like this...

sub func(&) { return shift; };
my $foo = func { ... };

func() has a & prototype, so there's no need for the "sub" part. It would
seem to be just a kinda unnecessary optimization to remove the sub, except it
has subtle effects on how the prototype is parsed. These are revealed by the
larna.t tests.

sub func(&) { return shift; };
my $a = [ func { 123 }, 1 ];

sub func(&) { return shift; };
my $a = [ func sub { 123 }, 1 ];

The top one works, the bottom one fails "too many arguments for main::func".
The prototype must be getting confused. This may be why it fixed a 5.10 bug,
there may have been a prototype glitch. Or maybe this behavior is a prototype
glitch. Either way it works now on 5.10.0 and 5.14.1.

The bug it revealed is I got the logic backwards, so the code wasn't applying
to anonymous routines. So you're right that I was throwing away the $before
argument for all named subs. Devel::Declare was taking care of it, because
$before was false so it handled it itself. There's no need to replicate their
functionality at all! inject_if_block() now just adds our BEGIN functionality
only for named subroutines when compile_at_BEGIN is on.

@barefootcoder
Copy link
Contributor

Okay, I mostly followed all that. I guess my main question, though, is why do we need

sub func(&) { return shift; };
my $foo = func { ... };

when it seems like

my $foo = sub { ... };

would work just as well? And also not engender the problem you describe from larna.t ...

Still planning on jumping on merging-and-releasing this branch next, BTW. JIC you thought I was falling down on the job over here. :-D

@schwern
Copy link
Contributor Author

schwern commented Oct 27, 2012

On 2012.10.26 8:11 PM, Buddy Burden wrote:

Okay, I mostly followed all that. I guess my main question, though, is why do
we /need/

|sub func(&) { return shift; };
my $foo = func { ... };

when it seems like

my $foo = sub { ... };

would work just as well? And also not engender the problem you describe from
larna.t ...

You'll have to ask the DD folks about that. I suspect its because DD stops
the parser just after the "func" or "method" keyword, so it has to do
something with it. It might be an artifact of earlier DD versions they never
got rid of. I've tried several times to hack up DD to get rid of it and failed.

Still planning on jumping on merging-and-releasing this branch next, BTW. JIC
you thought I was falling down on the job over here. :-D

Nope, you seem to be well on top of things.

  1. Not allowed to add "In accordance with the prophesy" to the end of
    answers I give to a question an officer asks me.
    -- The 213 Things Skippy Is No Longer Allowed To Do In The U.S. Army
    http://skippyslist.com/list/

@barefootcoder
Copy link
Contributor

Seems to work on all Perl's I tried it on (5.8.9, 5.10.1, 5.12.4, 5.14.2, 5.16.1). The change you made now makes it so that the inject_if_block in MSM is no longer redundant, so that will be staying. I'm ready to merge this in, although I'm still trying to figure out why I haven't seen any CPANTesters reports on the last dev release yet. But I may just go ahead and whip out another one and see if that one fares any better.

barefootcoder added a commit that referenced this pull request Nov 8, 2012
@barefootcoder barefootcoder merged commit 920e2d5 into master Nov 8, 2012
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants