evalEmpire / method-signatures

Method and function declarations with signatures, no source filter
http://metacpan.org/pod/Method::Signatures
Other
33 stars 35 forks source link

Become a wrapper around Function::Parameters #116

Open schwern opened 9 years ago

schwern commented 9 years ago

I'm taking a look at Function::Parameters and have come to conclusion that it's vastly superior. It uses Perl keywords rather than Devel::Declare (that solves a lot of problems right there). Its parser is implemented in C (faster and more reliable than PPI). Its syntax is more in line with Perl 5 signatures.

I propose we turn Method::Signatures into a thin compatibility wrapper around Function::Parameters.

I further propose that we declare Method::Signatures obsolete. Method::Signatures has hit the limit of what Devel::Declare can do, and its syntax is not in line with Perl 5.

I'm working with @mauke to add some missing features as options so I can write a nearly complete compatibility wrapper. So far it's been going very smooth and has even fixed some long standing bugs.

The down side is Function::Parameters requires 5.14. It uses PL_keyword_plugin which was introduced in 5.14, there's no work around. I'm ok with this, but I know @barefootcoder has needed 5.8 compatibility.

I've used Method::Signatures extensively in Gitpan and love using it, but I've also hit its unsolvable limitations (particularly with messing up line numbers). I'm happy to junk the existing code base if it makes the tool better.

barefootcoder commented 9 years ago

Well, I have two issues with this plan:

My vision for what Method::Signatures could become is that when you do

use Method::Signatures;

you get a consistent, predictable set of signature syntax that works on all Perl versions and gives you the best possible implemenation for your particular version. I think this goal is achievable with minimal effort, and I'd hoped to already be working on it by now, but my schedule has not been kind to me over the last year or so. But I think we could work out a plan to achieve this if we try.

thoughtstream commented 9 years ago

I would certainly be in favour of moving M::S away from Devel::Declare and onto a saner platform, such as the pluggable keyword interface.

This would, amongst other benefits, support my nefarious plans for a keyword based inside-out class declaration module and a keyword based Perl6-like macro facility. I already have a prototype for ecah of those, but they've been on hold for over a year because the keywords interfaces utterly refuse to play nicely with the existing implementation of Method::Signatures (i.e. with the dark magics of Devel::Declare).

I very much like Buddy's vision of a progressive thin wrapper providing interface and feature stability across the full range of deployed Perl versions. And I agree that Kavorka seems like a much closer fit, both in terms of its current feature set, and also in terms of its developer's goals and ambitions.

Not that I think for a moment that I should have a vote or a say in this decision. Just a considered opinion. ;-)

Damian

barefootcoder commented 9 years ago

Not that I think for a moment that I should have a vote or a say in this decision. Just a considered opinion. ;-)

Thanks for weighing in Damian; I appreciate you sharing your thoughts.

schwern commented 9 years ago

I agree Kavorka is a better fit. I'll start prototyping a wrapper. @tobyink, what do you think?

My main problem with maintaining < 5.14 compatibility (even Debian Stable is using 5.14) is maintaining bug and feature compatibility between the two implementations. Aside from the extra work, Devel::Declare just might not be able to do what a PL_keywords implementation can.

In fact, Kavorka looks so good... do we need to continue work on Method::Signatures except for backwards compatibility?

thoughtstream commented 9 years ago

Schwern observed:

My main problem with maintaining < 5.14 compatibility (even Debian Stable is using 5.14) is maintaining bug and feature compatibility between the two implementations. Aside from the extra work, Devel::Declare just might not be able to do what a PL_keywords implementation can.

Is that strictly necessary? When people move to a newer version of Perl, they know there will be added features. Why should it not be the same with M::S? If you're using 5.008 through 5.012, you get the subset of M::S that those ancient Perl versions permit (i.e. the current feature set). If you're using 5.014+, you get the full M::S-over-Kavorka experience.

In fact, Kavorka looks so good... do we need to continue work on Method::Signatures except for backwards compatibility?

I'm inclined to agree. I guess that really only depends on how susceptib^Wopen Toby is to our future evil ideas. >;-)

For example, I had plans to propose that M::S eventually support (under 5.22+)

func foo(&code, @list) { ... }

which would be the equivalent of:

sub foo (CodeRef $coderef, @list) {
    my sub code { goto &$coderef }
    ...
}

which would be very useful for functional programming in Perl (especially given Kavorka's already totally awesome multiple dispatch support).

I guess the other question is: how does Kavorka's performance compare to the current M::S implementation. Knowing Toby, I fully expect it's very good, but it would be useful to have a benchmark them both (and maybe Function::Parameters as well?)

Damian

schwern commented 9 years ago

Is that strictly necessary? When people move to a newer version of Perl, they know there will be added features. Why should it not be the same with M::S?

While that's true for Perl, that's not true for modules. The behavior of modules is expected to remain consistent across Perl versions. Otherwise you run into Perl version compatibility problems that aren't about Perl. You test your code on 5.18 and it works fine, you test it on 5.12 and it works different.

We can make it work that way, and it's possible to mitigate some of the problems with version checks and errors, but I feel that accepts that Method::Signatures has become a cross-version compatibility wrapper, which I'm ok with.

...which would be very useful for functional programming in Perl

My mind doesn't bend that way yet. I'm just going to believe you. It's a good bet. My only comment is that magic should be triggered with an is trait, because it isn't at all immediately obvious that's what &foo should do. That's a topic for another issue.

I guess the other question is: how does Kavorka's performance compare to the current M::S implementation.

That's what I'll be investigating. All I've done yet is see how fast they load themselves...

155ms is unacceptable, but I presume there's plenty of low hanging optimization fruit so I'm not worried yet. Function::Parameters' performance is drool-worthy, its implemented in hand written and fairly readable C.

What's more important is how fast they compile signatures and how fast the runtime calls are.

thoughtstream commented 9 years ago

Schwern observed:

but I feel that accepts that Method::Signatures has become a cross-version compatibility wrapper, which I'm ok with.

Likewise.

My mind doesn't bend that way yet. I'm just going to believe you. It's a good bet.

Thank-you. I think you're going to see a lot more interest in FP now that Perl 6 is about to land for real (because that Perl dialect has vastly more support for the paradigm). But, as that interest grows, Perl 5 developers are going to want to drink the kool-aid too, and it would be great if tools like Kavorka and M::S can provide as much support for that as possible.

Function::Parameters 18 ms Method::Signatures 65 ms Kavorka 155 ms

155ms is unacceptable, but I presume there's plenty of low hanging optimization fruit so I'm not worried yet.

Fair enough. I haven't looked inside it at all, but as it's associated with the Moo ecosystem, it may well be preloading a great many other components that could be deferred to "on demand".

Function::Parameters' performance is drool-worthy, its implemented in hand written and fairly readable C.

But with only about 1/5 the Kavorka feature set. :-(

What's more important is how fast they compile signatures and how fast the runtime calls are.

Indeed!

Damian

tobyink commented 7 years ago

Kavorka is optimized for run-time speed rather than compile-time speed.

#!/usr/bin/env perl

use v5.14;
use strict;
use warnings;
use Benchmark qw(cmpthese);

my @implementations;

package Eg_Kavorka {
    use Kavorka;
    method eg (Int $x, Str $y) {
        return [$x, $y];
    }
    push @implementations, __PACKAGE__;
}

package Eg_FP {
    use Function::Parameters;
    use MooseX::Types::Moose qw( Int Str );
    method eg (Int $x, Str $y) {
        return [$x, $y];
    }
    push @implementations, __PACKAGE__;
}

package Eg_MS {
    use Method::Signatures;
    method eg (Int $x, Str $y) {
        return [$x, $y];
    }
    push @implementations, __PACKAGE__;
}

for my $pkg (@implementations) {
    join(' ', @{$pkg->eg(99, 'bottles of beer')}) eq '99 bottles of beer'
        or die "$pkg is broken";
}

cmpthese -1, {
    map {
        my $pkg = $_;
        $pkg => sub {
            $pkg->eg($_, 'xyz') for 1 .. 1000;
        };
    } @implementations
};

__END__
             Rate      Eg_FP      Eg_MS Eg_Kavorka
Eg_FP      13.0/s         --       -92%       -97%
Eg_MS       161/s      1138%         --       -63%
Eg_Kavorka  439/s      3269%       172%         --
tobyink commented 7 years ago

Also, I'm being cruel to Function::Parameters there. If you replace MooseX::Types::Moose with Types::Standard, it will be pretty much as fast as Kavorka, for a small number of parameters. If a signature includes a lot of parameters, Kavorka will probably creep ahead again slightly.

barefootcoder commented 5 years ago

You know, it's occurred to me that I never posted what my hold-ups here were. Probably because I had grand schemes of figuring out what the actual problem was and possibly proposing a solution. But I can see now that's never going to happen. :-/

The issues I ran into with trying to convert existing Method::Signatures code into Kavorka (which I wanted to do partially as a test run and partially to see what options and/or plugins I'd have to use to recreate MSig's interface) seemed to have to do with the parameters being parsed too late. I'm pretty sure this is because MSig uses Devel::BeginLift (or equivalent) whereas Kavorka doesn't. But I could never figure out how to make Kavorka match our behavior. So all my simple test conversions were a failure.

I would still love to solve this one day. But I'm not sure how to proceed, exactly, and I've just never had the time to sink into it since I switched jobs about 5 years ago.