perl sucks - and what to do about it
DESCRIPTION
(originally presented at YAPC::Europe::2007) No-one is as critical about something as those that love it dearly. Mark Fowler has been collecting complaints from professional Perl developers for years about what warts still remain with the language when strict and warnings are turned on. Are these problems unsolvable? A veteran Perl programmer himself Mark attempted to try and solve these issues - and then turned to the experts, the people who write books on Perl, the people who maintain the perl interpreter itself, for help. This is what he learned...TRANSCRIPT
Perl Sucks!(and what to do about it)
What this talk is not
• “Wah, no one uses ‘use strict’”
• “People’s perception of Perl is wrong”
• “The CPAN/mailing list/a other website isn’t exactly how I like it”
• “The garbage collection de-allocation routine isn’t very efficent”
What this talk is
• What’s a few major annoyances with Perl
• What we the humble programmer can do to work around them
~/bin
scp ~/bin nethost:
ssh newhost
jabme -m ‘compile done’
Module “Jabber::Lite” not found
-bash: jabme: /usr/local/bin/perl: bad interpreter: No
such file or directory
My Scripts Need
• A particular version of Perl
• A set of Perl modules
PAR
#!/usr/bin/perl
use strict;use warnings;
use XML::LibXML;use Template;use DBD::SQLite;use CGI;use Parse::RecDescent;use List::MoreUtils;use Moose;
print "Hello World\n";
Make an executable
• perl -MCPAN -e ‘install PAR::Packer’
• pp -o hellow hellow.pl
• ...copy “hellow” to new computer
• ./hellow
Hello World
#!/usr/bin/perl
use strict;use warnings;
print "Hello World\n";
Build our own Perl and ship the whole thing
Get Stable Perl
• lwp-request $CPAN_URL > perl-5.8.8.tar.gz
• gunzip -c perl-5.8.8.tar.gz | tar -xvf -
• cd perl-5.8.8
Tell it where to go
• mkdir -p /User/mark/bin/perl5.8.8
• ./configure.gnu --prefix=/User/mark/bin/perl5.8.8
Install it
• make
• make test
• make install
We now have our own perl in ~/bin
We can install it’s own modules
~/bin/perl5.8.8/bin/perl -MCPAN -e ‘install
Template’
Problem: different paths
• /home/mark/bin/myperl
• /home/mfowler/bin/myperl
• /home/nisuser/bin/myperl
mv ~/bin/perl5.8.8whatever
whatever/bin/perl -e ‘use Storable’
Can't locate Storable.pm in @INC (@INC contains: /User/mark/bin/perl5.8.8/lib/5.8.8/darwin-2level /User/mark/bin/perl5.8.8/lib/5.8.8 /User/mark/bin/perl5.8.8/lib/site_perl/
5.8.8/darwin-2level /User/mark/bin/perl5.8.8/lib/site_perl/5.8.8 /User/mark/bin/perl5.8.8/lib/
site_perl .) at -e line 1.
Can't locate Storable.pm in @INC (@INC contains: /User/mark/bin/perl5.8.8/lib/5.8.8/darwin-2level /User/mark/bin/perl5.8.8/lib/5.8.8 /User/mark/bin/perl5.8.8/lib/site_perl/
5.8.8/darwin-2level /User/mark/bin/perl5.8.8/lib/site_perl/5.8.8 /User/mark/bin/perl5.8.8/lib/
site_perl .) at -e line 1.
Can't locate Storable.pm in @INC (@INC contains: ../lib/5.8.8/darwin-2level
../lib/5.8.8../lib/site_perl/5.8.8/darwin-2level
../lib/site_perl/5.8.8../lib/site_perl .) at -e line 1.
bleed to the rescue
Get Bleed Perl
• lwp-request $CPAN_URL > perl-5.9.5.tar.gz
• gunzip -c perl-5.9.5.tar.gz | tar -xvf -
• cd perl-5.9.5
BETA
Tell it where to go
• mkdir -p /User/mark/bin/perl5.9.5
• ./Configure -Dusedevel -Dprefix=/User/mark/bin/perl5.9.5 -Duserelocatableinc -d
BETA
Tell it where to go
• mkdir -p /User/mark/bin/perl5.9.5
• ./Configure -Dusedevel -Dprefix=/User/mark/bin/perl5.9.5 -Duserelocatableinc -d
BETA
Install it
• make
• make test
• make install
BETA
mv ~/bin/perl5.9.5whatever
BETA
whatever/bin/perl5.9.5 -e ‘use Storable’
BETA
Exception Handling
try { throw new NoCheeseException(“redo”);} catch (NoCheeseException e) { system.err.println(e.toString());}
Java
eval { die new NoCheeseError->new(“redo”);};if (blessed($@) && $@->isa(“NoCheeseException”)) { print STDERR $@;} elsif ($@) { die $@ }
Perl
Perl has SUCKY SYNTAX
Sins include:
eval { die new NoCheeseError->new(“redo”);};if (blessed($@) && $@->isa(“NoCheeseException”)) { print STDERR $@;} elsif ($@) { die $@ }
Perl
die “stop my program”;
die “some catchable exception”;
eval { die new NoCheeseError->new(“redo”);};if (blessed($@) && $@->isa(“NoCheeseException”)) { print STDERR $@;} elsif ($@) { die $@ }
Perl
eval “some code to be compiled”;
eval { # run some code to catch errors in};
eval { die new NoCheeseError->new(“redo”);};if (blessed($@) && $@->isa(“NoCheeseException”)) { print STDERR $@;} elsif ($@) { die $@ }
Perl
eval { die new NoCheeseError->new(“redo”);};if (blessed($@) && $@->isa(“NoCheeseException”)) { print STDERR $@;} elsif ($@) { die $@ }
Perl
We can fix it!
try { throw NoCheeseException “redo”;}catch NoCheeseException with { print STDERR $@;};
(still) Perl
try { throw NoCheeseException “redo”;}catch NoCheeseException with { print STDERR $@;}catch AnotherError with { print STDERR “oops\n”;};
try { throw NoCheeseException “redo”;}catch NoCheeseException with { print STDERR $@;}catch AnotherError with { print STDERR “oops\n”;};
try( sub { throw NoCheeseException “redo”;},catch NoCheeseException with(sub { print STDERR $@;},catch AnotherError with(sub { print STDERR “oops\n”;})));
try( sub { throw NoCheeseException “redo”;},catch NoCheeseException with(sub { print STDERR $@;},catch AnotherError with(sub { print STDERR “oops\n”;})));
try( sub { NoCheeseException->throw( “redo” );},NoCheeseException->catch( with(sub { print STDERR $@;},AnotherError->catch( with(sub { print STDERR “oops\n”;})))));
sub with (&;@) { return @_}
try( sub { NoCheeseException->throw( “redo” );},NoCheeseException->catch( with(sub { print STDERR $@;},AnotherError->catch( with(sub { print STDERR “oops\n”;})))));
try( sub { NoCheeseException->throw( “redo” );},NoCheeseException->catch( sub { print STDERR $@;},AnotherError->catch( sub { print STDERR “oops\n”;})));
package OurErrorSuperclass;
sub catch { my $class = shift; my $action = shift; return +{ class => $class, action => $action }, @_;}
try( sub { NoCheeseException->throw( “redo” );},NoCheeseException->catch( sub { print STDERR $@;},AnotherError->catch( sub { print STDERR “oops\n”;})));
try( sub { NoCheeseException->throw( “redo” );}, NoCheeseException->catch( sub { print STDERR $@;}, +{ class => “AnotherError”, action => sub { print STDERR “oops\n” }}));
try( sub { NoCheeseException->throw( “redo” );}, +{ class => “NoCheeseException”, action => sub { print STDERR $@; }}, +{ class => “AnotherError”, action => sub { print STDERR “oops\n” }});
try( sub { NoCheeseException->throw( “redo” );}, +{ class => “NoCheeseException”, action => sub { print STDERR $@; }}, +{ class => “AnotherError”, action => sub { print STDERR “oops\n” }});
try( sub { NoCheeseException->throw( “redo” );}, +{ class => “NoCheeseException”, action => sub { print STDERR $@; }}, +{ class => “AnotherError”, action => sub { print STDERR “oops\n” }});
try( sub { NoCheeseException->throw( “redo” );}, +{ class => “NoCheeseException”, action => sub { print STDERR $@; }}, +{ class => “AnotherError”, action => sub { print STDERR “oops\n” }});
try { throw NoCheeseException “redo”;}catch NoCheeseException with { print STDERR $@;};
(still) Perl
sub foo { try { return “This doesn’t return from foo”; } catch NoCheeseException with { print STDERR $@; };}
sub foo { eval { return “This doesn’t return from foo”; }; if ($@) { .... }}
sub foo { try { return “This doesn’t return from foo”; } catch NoCheeseException with { print STDERR $@; };}
sub foo { try { rreturn “This doesn’t return from foo”; } catch NoCheeseException with { print STDERR $@; } and return allowed;}
sub foo { try { rreturn “This doesn’t return from foo”; } catch NoCheeseException with { print STDERR $@; } and return allowed;}
MyException
NoCheeseException
NoDairyException
NoMilkException
NoSpreadException
NoEdamException NoStiltonException NoBrieException
NoButterException
NoMargException
package NoDairyException;our @ISA = qw(MyError);
package NoMilkException;our @ISA = qw(NoDairyException);
package NoSpreadException;our @ISA = qw(NoDairyException);
package NoButterException;our @ISA = qw(NoSpreadException);
package NoMargException;our @ISA = qw(NoMargeException);
package NoCheeseException;our @ISA = qw(NoDairyException);
package NoEdamException;our @ISA = qw(NoCheeseException);
package NoStiltonException;our @ISA = qw(NoCheeseException);
package NoBrieException;our@ISA = qw(NoCheeseException);
Exceptions::define { exception NoDairyException; exception NoSpreadException extends NoDairyException; exception NoButterException extends NoSpreadException; exception NoMargException extends NoSpreadException; exception NoMilkException extends NoDairyException; exception NoCheeseException extends NoDairyException; exception NoEdamException extends NoCheeseException; exception NoStiltonException extends NoCheeseException; exception NoBrieException extends NoCheeseException;};
But it’s a scripting language!
Don’t you just love the Template Toolkit?
bash$ tpage[% FOR a = [1..5]; a; END %]^D12345bash$
#!perl
$whereami = “Vienna”;print “Hello $whereami!\n”;
#!tpage
[% whereami = “Vienna” -%]Hello [% whereami %]!
bash$ ./hellov.tp
bash$ ./hellov.tp -bash: ./hellov.tp: tpage: bad interpreter: No such file or directory
#!tpage
[% whereami = “Vienna” -%]Hello [% whereami %]!
where bash finds theExecutable code to
load into memory
bash$ cat tpage#!/usr/bin/perl -wuse strict;use Template;use AppConfig;…
Two possible solutions
Method one: Abuse source filters
• “Source filters are a way to change your source code before perl gets to see it”
#!/usr/bin/perl
use strict;use warnings;
use EnableDebugging;
# DEBUG printing stuff outprint "hi\n";
#!/usr/bin/perl
use strict;use warnings;
use EnableDebugging;
;print STDERR “DEBUG: printing stuff out\n”;print "hi\n";
package EnableDebugging;use Filter::Simple;
FILTER { s{#\s*DEBUG\s+(.*)} {;print STDERR q<DEBUG: $1>, "\n";};};
1;
package EnableDebugging;use Filter::Simple;
FILTER { s{#\s*DEBUG\s+(.*)} {;print STDERR q<DEBUG: $1>, "\n";};};
1;
package tpage;use Filter::Simple;
FILTER { s{#\s*DEBUG\s+(.*)} {;print STDERR q<DEBUG: $1>, "\n";};};
1;
package tpage;use Filter::Simple;
FILTER { s{#\s*DEBUG\s+(.*)} {;print STDERR q<DEBUG: $1>, "\n";};};
1;
package tpage;use Filter::Simple;
FILTER { $template .= $_; $_ = “”;};
1;
package tpage;use Filter::Simple;
FILTER { $template .= $_; $_ = “”;};
END { use Template; Template->new->process(\$template); }
#!/usr/bin/perluse tpage;
[%- whereami = “Vienna” -%]Hello [% whereami %]!
2. Build our own executable
#include <EXTERN.h>#include <perl.h>
static PerlInterpreter *my_perl;
int main(int argc, char **argv, char **env){ char *embedding[] = { "", "-e", "0" };
PERL_SYS_INIT3(&argc,&argv,&env); my_perl = perl_alloc(); perl_construct(my_perl);
perl_parse(my_perl, NULL, 3, embedding, NULL); PL_exit_flags |= PERL_EXIT_DESTRUCT_END; perl_run(my_perl);
eval_pv("print qq'oh hai\n’;", TRUE); perl_destruct(my_perl); perl_free(my_perl); PERL_SYS_TERM();}
stolen from “perldoc perlembed”)(
#include <EXTERN.h>#include <perl.h>
static PerlInterpreter *my_perl;
int main(int argc, char **argv, char **env){ char *embedding[] = { "", "-e", "0" };
PERL_SYS_INIT3(&argc,&argv,&env); my_perl = perl_alloc(); perl_construct(my_perl);
perl_parse(my_perl, NULL, 3, embedding, NULL); PL_exit_flags |= PERL_EXIT_DESTRUCT_END; perl_run(my_perl);
eval_pv("print qq'o hai\n';", TRUE); perl_destruct(my_perl); perl_free(my_perl); PERL_SYS_TERM();}
#include <EXTERN.h>#include <perl.h>
static PerlInterpreter *my_perl;
int main(int argc, char **argv, char **env){ char *embedding[] = { "", "-e", "0" };
PERL_SYS_INIT3(&argc,&argv,&env); my_perl = perl_alloc(); perl_construct(my_perl);
perl_parse(my_perl, NULL, 3, embedding, NULL); PL_exit_flags |= PERL_EXIT_DESTRUCT_END; perl_run(my_perl);
eval_pv("print qq’o hai\n’;", TRUE); perl_destruct(my_perl); perl_free(my_perl); PERL_SYS_TERM();}
cc -o hellow hellow.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
bash$ ./hellowo hai
#include <EXTERN.h>#include <perl.h>
static PerlInterpreter *my_perl;
int main(int argc, char **argv, char **env){ char *embedding[] = { "", "-e", "0" };
PERL_SYS_INIT3(&argc,&argv,&env); my_perl = perl_alloc(); perl_construct(my_perl);
perl_parse(my_perl, NULL, 3, embedding, NULL); PL_exit_flags |= PERL_EXIT_DESTRUCT_END; perl_run(my_perl);
eval_pv("print qq'o hai\n';", TRUE); perl_destruct(my_perl); perl_free(my_perl); PERL_SYS_TERM();}
#include <EXTERN.h>#include <perl.h>
static PerlInterpreter *my_perl;
int main(int argc, char **argv, char **env){ char *embedding[] = { "", "-e", "0" };
PERL_SYS_INIT3(&argc,&argv,&env); my_perl = perl_alloc(); perl_construct(my_perl);
perl_parse(my_perl, NULL, 3, embedding, NULL); PL_exit_flags |= PERL_EXIT_DESTRUCT_END; perl_run(my_perl);
eval_pv("print qq’o hai\n’;", TRUE); perl_destruct(my_perl); perl_free(my_perl); PERL_SYS_TERM();}
#include <EXTERN.h>#include <perl.h>
static PerlInterpreter *my_perl;
int main(int argc, char **argv, char **env){ char *embedding[] = { "", "-e", "0", argv[0]};
PERL_SYS_INIT3(&argc,&argv,&env); my_perl = perl_alloc(); perl_construct(my_perl);
perl_parse(my_perl, NULL, 4, embedding, NULL); PL_exit_flags |= PERL_EXIT_DESTRUCT_END; perl_run(my_perl);
eval_pv("print qq’o hai\n’;", TRUE); perl_destruct(my_perl); perl_free(my_perl); PERL_SYS_TERM();}
#include <EXTERN.h>#include <perl.h>
static PerlInterpreter *my_perl;
int main(int argc, char **argv, char **env){ char *embedding[] = { "", "-e", "0", argv[0]};
PERL_SYS_INIT3(&argc,&argv,&env); my_perl = perl_alloc(); perl_construct(my_perl);
perl_parse(my_perl, NULL, 4, embedding, NULL); PL_exit_flags |= PERL_EXIT_DESTRUCT_END; perl_run(my_perl);
eval_pv("print qq’o hai\n’;", TRUE); perl_destruct(my_perl); perl_free(my_perl); PERL_SYS_TERM();}
#include <EXTERN.h>#include <perl.h>
static PerlInterpreter *my_perl;
int main(int argc, char **argv, char **env){ char *embedding[] = { "", "-e", "0", argv[0]};
PERL_SYS_INIT3(&argc,&argv,&env); my_perl = perl_alloc(); perl_construct(my_perl);
perl_parse(my_perl, NULL, 4, embedding, NULL); PL_exit_flags |= PERL_EXIT_DESTRUCT_END; perl_run(my_perl);
eval_pv( “use Template \ Template->new->process($ARGV[0])", TRUE); perl_destruct(my_perl); perl_free(my_perl); PERL_SYS_TERM();}
cc -o mytt mytt.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
#!mytt
[% whereami = “Vienna” -%]Hello [% whereami %]!
now Executable code toload into memory
#include <EXTERN.h>#include <perl.h>
static PerlInterpreter *my_perl;
int main(int argc, char **argv, char **env){ char *embedding[] = { "", "-e", "0", argv[0]};
PERL_SYS_INIT3(&argc,&argv,&env); my_perl = perl_alloc(); perl_construct(my_perl);
perl_parse(my_perl, NULL, 4, embedding, NULL); PL_exit_flags |= PERL_EXIT_DESTRUCT_END; perl_run(my_perl);
eval_pv( “use Template \ Template->new->process($ARGV[0])", TRUE); perl_destruct(my_perl); perl_free(my_perl); PERL_SYS_TERM();}
“hellov.tp”
#include <EXTERN.h>#include <perl.h>
static PerlInterpreter *my_perl;
int main(int argc, char **argv, char **env){ char *embedding[] = { "", "-e", "0", argv[0]};
PERL_SYS_INIT3(&argc,&argv,&env); my_perl = perl_alloc(); perl_construct(my_perl);
perl_parse(my_perl, NULL, 4, embedding, NULL); PL_exit_flags |= PERL_EXIT_DESTRUCT_END; perl_run(my_perl);
eval_pv( “use Template \ Template->new->process($ARGV[0])", TRUE); perl_destruct(my_perl); perl_free(my_perl); PERL_SYS_TERM();}
“hellov.tp”
We’ve already seen source filters
ALPHA
• Pure Perl parser
• Only parses a subset of Perl
• Can’t tell the difference between certain Perl constructs
• This said - very very good at what it does
PPIBETA
MAD
ALPHA
./configure.gnu --prefix=~/bin/perl595 -Dusedevel -Dmad=y
make && make test && make install
ALPHA
my $a = 1;my $b = 2;
print $a + $b;
ALPHA
PERL_XMLDUMP="foo.xml" ./perl foo.pl
ALPHA
<op_leave seq="0 -> DONE" targ="1" flags="VOID,KIDS,PARENS" private="REFCOUNTED" refcnt="1"> <op_enter seq="1 -> 2" /> <op_null seq="0 -> (2)" flags="VOID"> <madprops> <mad_sv key=";" val=""/> </madprops> </op_null> <op_nextstate seq="2 -> 3" flags="VOID" line="1" package="main"> <madprops> <mad_sv key=";" val=";"/> <mad_sv key="#;" val="
"/> </madprops> </op_nextstate> <op_sassign seq="5 -> 6" flags="VOID,KIDS,STACKED"> <madprops> <mad_sv key="o" val="="/> <mad_sv key="_o" val=" "/> </madprops> <op_const seq="3 -> 4" flags="SCALAR" IV="1"> <madprops> <mad_sv key="X" val="1"/> <mad_sv key="_X" val=" "/> </madprops> </op_const> <op_padsv seq="4 -> 5" targ="1" flags="SCALAR,REF,MOD,SPECIAL" private="INTRO"> <madprops> <mad_sv key="$" val="$a"/> <mad_sv key="_$" val=" "/> <mad_sv key="d" val="my"/> <mad_sv key="_d" val=""/> </madprops> </op_padsv> </op_sassign> <op_nextstate seq="6 -> 7" flags="VOID" line="2" package="main"> <madprops> <mad_sv key=";" val=";"/> <mad_sv key="#;" val="
"/> </madprops> </op_nextstate> <op_sassign seq="9 -> 10" flags="VOID,KIDS,STACKED"> <madprops> <mad_sv key="o" val="="/> <mad_sv key="_o" val=" "/> </madprops> <op_const seq="7 -> 8" flags="SCALAR" IV="2"> <madprops> <mad_sv key="X" val="2"/> <mad_sv key="_X" val=" "/> </madprops> </op_const> <op_padsv seq="8 -> 9" targ="2" flags="SCALAR,REF,MOD,SPECIAL" private="INTRO"> <madprops> <mad_sv key="$" val="$b"/> <mad_sv key="_$" val=" "/> <mad_sv key="d" val="my"/> </madprops> </op_padsv> </op_sassign> <op_nextstate seq="10 -> 11" flags="VOID" line="3" package="main"> <madprops> <mad_sv key=";" val=";"/> <mad_sv key="_;" val=""/> <mad_sv key="#;" val="
"/> </madprops> </op_nextstate> <op_print seq="15 -> 16" flags="SCALAR,KIDS"> <madprops> <mad_sv key="o" val="print"/> </madprops> <op_pushmark seq="11 -> 12" flags="SCALAR" /> <op_add seq="14 -> 15" targ="3" flags="SCALAR,KIDS"> <madprops> <mad_sv key="o" val="+"/> <mad_sv key="_o" val=" "/> </madprops> <op_padsv seq="12 -> 13" targ="1" flags="SCALAR"> <madprops> <mad_sv key="$" val="$a"/> <mad_sv key="_$" val=" "/> </madprops> </op_padsv> <op_padsv seq="13 -> 14" targ="2" flags="SCALAR"> <madprops> <mad_sv key="$" val="$b"/> <mad_sv key="_$" val=" "/> </madprops> </op_padsv> </op_add> </op_print> <op_null seq="0 -> (16)" flags="VOID" /></op_leave>
<op_leave seq="0 -> DONE" targ="1" flags="VOID,KIDS,PARENS"
private="REFCOUNTED" refcnt="1">
<op_enter seq="1 -> 2" /> <op_null seq="0 -> (2)" flags="VOID">
<madprops> <mad_sv key=";" val=""/>
</madprops> </op_null>
<op_nextstate seq="2 -> 3" flags="VOID" line="1"
package="main"> <madprops>
<mad_sv key=";" val=";"/> <mad_sv key="#;" val="
"/>
</madprops> </op_nextstate>
<op_sassign seq="5 -> 6" flags="VOID,KIDS,STACKED">
<madprops> <mad_sv key="o" val="="/> <mad_sv key="_o" val=" "/>
</madprops> <op_const seq="3 -> 4" flags="SCALAR"
IV="1"> <madprops>
<mad_sv key="X" val="1"/> <mad_sv key="_X" val=" "/>
</madprops> </op_const>
<op_padsv seq="4 -> 5" targ="1" flags="SCALAR,REF,MOD,SPECIAL"
private="INTRO"> <madprops>
<mad_sv key="$" val="$a"/> <mad_sv key="_$" val=" "/>
<mad_sv key="d" val="my"/> <mad_sv key="_d" val=""/>
</madprops> </op_padsv>
</op_sassign> <op_nextstate seq="6 -> 7" flags="VOID"
line="2" package="main">
<madprops> <mad_sv key=";" val=";"/>
<mad_sv key="#;" val="
"/> </madprops> </op_nextstate>
<op_sassign seq="9 -> 10" flags="VOID,KIDS,STACKED">
<madprops> <mad_sv key="o" val="="/> <mad_sv key="_o" val=" "/>
</madprops> <op_const seq="7 -> 8" flags="SCALAR"
IV="2"> <madprops>
<mad_sv key="X" val="2"/> <mad_sv key="_X" val=" "/>
</madprops> </op_const>
<op_padsv seq="8 -> 9" targ="2" flags="SCALAR,REF,MOD,SPECIAL"
private="INTRO"> <madprops>
<mad_sv key="$" val="$b"/> <mad_sv key="_$" val=" "/>
<mad_sv key="d" val="my"/> </madprops>
</op_padsv> </op_sassign>
<op_nextstate seq="10 -> 11" flags="VOID" line="3"
package="main"> <madprops>
<mad_sv key=";" val=";"/> <mad_sv key="_;" val=""/>
<mad_sv key="#;" val="
"/> </madprops> </op_nextstate>
<op_print seq="15 -> 16" flags="SCALAR,KIDS"> <madprops>
<mad_sv key="o" val="print"/> </madprops>
<op_pushmark seq="11 -> 12" flags="SCALAR" /> <op_add seq="14 -> 15" targ="3"
flags="SCALAR,KIDS"> <madprops>
<mad_sv key="o" val="+"/> <mad_sv key="_o" val=" "/>
</madprops> <op_padsv seq="12 -> 13" targ="1"
flags="SCALAR"> <madprops>
<mad_sv key="$" val="$a"/> <mad_sv key="_$" val=" "/>
</madprops> </op_padsv>
<op_padsv seq="13 -> 14" targ="2" flags="SCALAR">
<madprops> <mad_sv key="$" val="$b"/> <mad_sv key="_$" val=" "/>
</madprops> </op_padsv>
</op_add> </op_print>
<op_null seq="0 -> (16)" flags="VOID" /></op_leave>
ALPHA
B::Generate
• Can be used to create OP codes (i.e. compiled Perl code) directly from Perl
use B::Generate; # Do nothing, slowly. CHECK { my $null = new B::OP("null",0); my $enter = new B::OP("enter",0); my $cop = new B::COP(0, "hiya", 0); my $leave = new B::LISTOP("leave", 0, $enter, $null); $leave->children(3); $enter->sibling($cop); $enter->next($cop); $cop->sibling($null); $null->next($leave); $cop->next($leave);
# Tell Perl where to find our tree. B::main_root($leave); B::main_start($enter); }
optomize.pm
• Can be used to manipulate the OP codes after they’ve loaded
• Kinda like source filters for compiled bypecode
Use?
• PPI is reliable, but limited in it’s ability
• Easy to try to do too much with
• Other techniques are very unstable / new
• B::Generate
• optomize
• MAD
package main;use typesafety; # 'summary', 'debug';
my FooBar $foo; # establish type-checked variablesmy FooBar $bar; # FooBar is the base class of references $bar will holdmy BazQux $baz;
$foo = new FooBar; # this is okay, because $foo holds FooBars$bar = $foo; # this is okay, because $bar also holds FooBars# $foo = 10; # this would throw an error - 10 is not a FooBar# $baz = $foo; # not allowed - FooBar isn't a BazQux$foo = $baz; # is allowed - BazQux is a FooBar because of inheritance$bar = $foo->foo($baz, 1); # this is okay, as FooBar::foo() returns FooBars also
typesafety::check(); # perform type check static analysis
ALPHA
package main;use typesafety; # 'summary', 'debug';
my FooBar $foo; # establish type-checked variablesmy FooBar $bar; # FooBar is the base class of references $bar will holdmy BazQux $baz;
$foo = new FooBar; # this is okay, because $foo holds FooBars$bar = $foo; # this is okay, because $bar also holds FooBars# $foo = 10; # this would throw an error - 10 is not a FooBar# $baz = $foo; # not allowed - FooBar isn't a BazQux$foo = $baz; # is allowed - BazQux is a FooBar because of inheritance$bar = $foo->foo($baz, 1); # this is okay, as FooBar::foo() returns FooBars also
typesafety::check(); # perform type check static analysis
ALPHA
package main;use typesafety; # 'summary', 'debug';
my FooBar $foo; # establish type-checked variablesmy FooBar $bar; # FooBar is the base class of references $bar will holdmy BazQux $baz;
$foo = new FooBar; # this is okay, because $foo holds FooBars$bar = $foo; # this is okay, because $bar also holds FooBars# $foo = 10; # this would throw an error - 10 is not a FooBar# $baz = $foo; # not allowed - FooBar isn't a BazQux$foo = $baz; # is allowed - BazQux is a FooBar because of inheritance$bar = $foo->foo($baz, 1); # this is okay, as FooBar::foo() returns FooBars also
typesafety::check(); # perform type check static analysis
ALPHA
package main;use typesafety; # 'summary', 'debug';
my FooBar $foo; # establish type-checked variablesmy FooBar $bar; # FooBar is the base class of references $bar will holdmy BazQux $baz;
$foo = new FooBar; # this is okay, because $foo holds FooBars$bar = $foo; # this is okay, because $bar also holds FooBars# $foo = 10; # this would throw an error - 10 is not a FooBar# $baz = $foo; # not allowed - FooBar isn't a BazQux$foo = $baz; # is allowed - BazQux is a FooBar because of inheritance$bar = $foo->foo($baz, 1); # this is okay, as FooBar::foo() returns FooBars also
typesafety::check(); # perform type check static analysis
ALPHA