prototype::signatures xxx HERE BE DRAGONS xxx YAPC::EU 2008 Chia-liang Kao
May 06, 2015
prototype::signatures
xxx HERE BE DRAGONS xxx
YAPC::EU 2008Chia-liang Kao
Chia-liang Kao
高嘉良
CL
Best Practical
We Make RT
We Make SVK
We Make Prophet
We also do...something mad
Not really our official project
CLKAONUFFIN
Yuval visited me in Taiwan
We need something to hack on
• conference-driven development
• hiking-driven development
What would make myself hate software
• In Perl...
• my $self = shift;
• typechecking
Perl 5 has prototypes
• sub foo ($&@) {}
• not very useful
Perl 6 signatures
• sub fnord(Int $n, :$foo = 42, $raah is optional) {};
• Type
• Default
• optional
• named-based
• is rw, is ro, is copy
JFDI
Let’s do it
• In perl5
• without source filter
• how hard could it be?
• Some beers required.
• If you like what you see next, buy us beers!
prototype::signatures
• We got a prototype after a week
• http://code2.0beta.co.uk/moose/svn/Perl6-Declare
• to be renamed
• patches and tests welcome
Example
• sub6 fnord(Int $n, :$foo = 42, $raah?) {};
• fnord(p(foo => 99, raah => 123), 100);
• just like in Perl6:
• fnord(:foo<99>, :raah<123>, 100)
More examples
• sub6 fnord(Int $n, :$foo = 42, $raah?) {};
• fnord(n($foo), 100);
• just like in Perl6:
• fnord(:$foo, 100);
Traits
sub6 fib(Int $n) is cached {
return 1 if $n <= 1;
return fib($n-1) + fib($n-2);
}
Methods!
• method fnord(Int $n, :$foo = 42) {};
• you get $self, no more shift
• or if you don’t like it
• method fnord($this: Int $n, :$foo = 42) {};
• your own invocant variable
You see how it looks
• Now Let’s see how it works
• B::Scared
• No, B::Awesome actually
Devel::Declare
• Allows you to have your own declarator
• and use a callback to handle what’s in ()
• Hijacks parser
• Subroutine body parses normally
• micro source filtering
Perl6::Signature
• Parses Perl 6 signature syntax
• Just syntax
my $sig = Perl6::Signature->parse( ':($self: $x, Int $y = 42 where { $_ % 2 == 0 }, :$z is copy)');
Data::Bind
• Implements perl 6 binding for perl5
• copy, rw, ro
• No syntax
Declare + P6::Sig + Data::Bind
• Declaration
• method foo ($inv: Int $number, :$named) { ... };
• translated into:
• sub foo { my ( $inv, $number, $named); ... # data bind magic ... }
Declare + P6::Sig + Data::Bind
sub foo {
my ( $inv, $number, $named);
Data::Bind->bind_with_signature(\@_, $sig_of_foo);
}
Slow?
• yes, because binding needs to work with the Signature data structure.
• but we can fix it
• and it has been fixed
Plan 1
sub6 fnord(Int $n, :$foo = 42,
$raah is optional) is crazy {
};
Yes, Crazy will be the default
How?fnord(p(foo => 99, raah => 123), 100);
sub6 fnord(Int $n, :$foo = 42, $raah?) {};
Caller:
How?fnord(p(foo => 99, raah => 123), 100);
Rewrite the caller’s optreewhich will be used from the second call on
A custom Perl OP to shuffle the stack,and then call into fnord
B::Generate
• Rewrite the call site
• Static arguments
• Custom binding opcode
• Tailored for the call site
• Fast, flexible
Benchmark
Rate normal_sub sub6_crazynormal_sub 296479/s -- -21%sub6_crazy 373314/s 26% --
sub call_sub6_crazy { sub6_crazy(p(a => 1, b => 2, c => 3, d => 4, e => 5));}
sub call_normal_sub { normal_sub_hash(a => 1, b => 2, c => 3, d => 4, e => 5);}
Problems
Won’t work for
sub6 ($n, @a) { }
foo(1, @a)
foo(1, function_returns_array());
Plan 2
B::OPCheck
6 <1> entersub[t2] KS/TARG,3 ->7- <1> ex-list K ->62 <0> pushmark s ->33 <$> const[IV 1] sM ->44 <$> const[IV 2] sM ->5- <1> ex-rv2cv sK/3 ->-5 <#> gv[*foo] s/EARLYCV ->6
$ re.pl$ #concise foo(1,2)
Install Devel::REPL if you haven’t
=>
PL_checkPL_check is an array indexed by opcode number (op_type) that contains function pointers invoked as the last stage of optree compilation, per op.
This is how things like autobox.pm does the magic
B::OPChecksub dothis { my $op = $_[0]; push @results, $op->name;}
sub test { use B::OPCheck entersub => check => \&dothis; foo(1,2); printf "foo"; foo("dancing"); no B::OPCheck; foo(2,3);}
<=
<=
B::OPChecksub dothis { my $op = $_[0]; push @results, $op->name;}
6 <1> entersub[t2] KS/TARG,3 ->7- <1> ex-list K ->62 <0> pushmark s ->33 <$> const[IV 1] sM ->44 <$> const[IV 2] sM ->5- <1> ex-rv2cv sK/3 ->-5 <#> gv[*foo] s/EARLYCV ->6
B::OPCheck
• Remember the crazy thing that updates the caller? We can now do it in compile time!
• Did you go to Damian’s talk this morning?
• Macro! Constant folding! Anyone?
Come hack on it
• B::Excited
• Edge cases, B::Frustrated
• B::Simple and B::Template to make the B::Insane tree generation sane
• cleanup, tests, docs
More to come
• Runtime trace caching JIT optimization
• optimized specialized op code, llvm
• B::Template
• Method::Inline # real macros
Come hacking
#moose-dev
Thanks!