Readable Perl
Document Sample


/;{}def/#{def}def/$_={/TimesBoldexchselectfont}#/_{ rmovet
;/q{exch}#/x ; {/J q #}#/.{/T q #}#{stringwidth}#{}#{}# 14 s
260 40 moveto 90 rotate ; %/}};$0='"\e[7m \e[0m"';@ARGV=spli
q(ThePerl). q(Journal) x 220 ; q ; 0 T putinterval exch 7 J
; $_= q /m$ pop T($*!$"=!$ " )pop " * true% ? $ " $!" " !!
! charpath {!"""}pop $ pop{""!}pop ! neg{!#}pop 220 ! neg _{
Readable Perl
charpath clip " pop 0 " moveto 6{!!}pop $_= 105{!!}pop {$ !
pop{dup dup $ ! " pop pop q{"}pop 22{dup show}repeat {"}pop
neg{!#! $ "}pop ! 8 .65 mul{$ # # $}pop ! neg{"}pop _ pop{"
" { $ " ! ! ! $ " ! !" "#" #"!"""""! #" " # "m/;@ARGV=(@AR
0 "%};s/m[ou]|[\dAlnz.\n_{}]|\$_=//gx;s/(.)(?{$*=''})/('
GeekUp Liverpool, Tuesday 27 May, 2008
th
%2?'':"$0;").'pop;')x(ord($1)31).'$*'/gee;s/((.(\e\[.m)*|.)
; sub showpage {}
http://upcoming.yahoo.com/event/691199/
@P=split//,".URRUU\c8R";@d=split//,"\nrekcah xinU / lreP reh
@p{"r$p","u$p"}=(P,P);pipe"r$p","u$p";++$p;($q*=2)+=$f=!fork;map{
hakim.cassimally@gmail.com
($p{$_})&6];$p{$_}=/ ^$P/ix?$P:close$_}keys%p}p;p;p;p;p;map{
close$_}%p;wait until$?;map{/^r/&&<$_>}%p;$_=$d[$q];sleep ra
#:: ::| ::| .. :||:: 0| .| ::||| .:|. :||
open(Q,$0);while(<Q>){if(/^#(.*)$/){for(split('',$1)){$q=0;
/:.:/xg;s/:/../g;$Q=$_?length:$_;$q+=$q?$Q:$Q*20;}print chr(
#.: ::||| .||| :|||| ::||| ||:: :|||| .:|
/;{}def/#{def}def/$_={/TimesBold exch selectfont}#/_{rmovet
;/q{exch}#/x ; {/J q #}#/.{/T q #}#{stringwidth}#{}#{}# 14 s
/;{}def/#{def}def/$_={/TimesBoldexchselectfont}#/_{ rmovet
;/q{exch}#/x ; {/J q #}#/.{/T q #}#{stringwidth}#{}#{}# 14 s
260 40 moveto 90 rotate ; %/}};$0='"\e[7m \e[0m"';@ARGV=spli
q(ThePerl). q(Journal) x 220 ; q ; 0 T putinterval exch 7 J
; $_= q /m$ pop T($*!$"=!$ " )pop " * true% ? $ " $!" " !!
It's possible for
! charpath {!"""}pop $ pop{""!}pop ! neg{!#}pop 220 ! neg _{
charpath clip " pop 0 " moveto 6{!!}pop $_= 105{!!}pop {$ !
Perl programmers
pop{dup dup $ ! " pop pop q{"}pop 22{dup show}repeat {"}pop
to write messy
neg{!#! $ "}pop ! 8 .65 mul{$ # # $}pop ! neg{"}pop _ pop{"
" { $ " ! ! ! $ " ! !" "#" #"!"""""! #" " # "m/;@ARGV=(@AR
programs.
0 "%};s/m[ou]|[\dAlnz.\n_{}]|\$_=//gx;s/(.)(?{$*=''})/('
%2?'':"$0;").'pop;')x(ord($1)31).'$*'/gee;s/((.(\e\[.m)*|.)
; sub showpage {}
@P=split//,".URRUU\c8R";@d=split//,"\nrekcah xinU / lreP reh
@p{"r$p","u$p"}=(P,P);pipe"r$p","u$p";++$p;($q*=2)+=$f=!fork;map{
($p{$_})&6];$p{$_}=/ ^$P/ix?$P:close$_}keys%p}p;p;p;p;p;map{
close$_}%p;wait until$?;map{/^r/&&<$_>}%p;$_=$d[$q];sleep ra
#:: ::| ::| .. :||:: 0| .| ::||| .:|. :||
open(Q,$0);while(<Q>){if(/^#(.*)$/){for(split('',$1)){$q=0;
/:.:/xg;s/:/../g;$Q=$_?length:$_;$q+=$q?$Q:$Q*20;}print chr(
#.: ::||| .||| :|||| ::||| ||:: :|||| .:|
/;{}def/#{def}def/$_={/TimesBold exch selectfont}#/_{rmovet
;/q{exch}#/x ; {/J q #}#/.{/T q #}#{stringwidth}#{}#{}# 14 s
/;{}def/#{def}def/$_={/TimesBoldexchselectfont}#/_{ rmovet
;/q{exch}#/x ; {/J q #}#/.{/T q #}#{stringwidth}#{}#{}# 14 s
260 40 moveto 90 rotate ; %/}};$0='"\e[7m \e[0m"';@ARGV=spli
q(ThePerl). q(Journal) x 220 ; q ; 0 T putinterval exch 7 J
; $_= q /m$ pop T($*!$"=!$ " )pop " * true% ? $ " $!" " !!
It's possible for
! charpath {!"""}pop $ pop{""!}pop ! neg{!#}pop 220 ! neg _{
charpath clip " pop 0 " moveto 6{!!}pop $_= 105{!!}pop {$ !
Perl programmers
pop{dup dup $ ! " pop pop q{"}pop 22{dup show}repeat {"}pop
to write messy
neg{!#! $ "}pop ! 8 .65 mul{$ # # $}pop ! neg{"}pop _ pop{"
" { $ " ! ! ! $ " ! !" "#" #"!"""""! #" " # "m/;@ARGV=(@AR
programs.
0 "%};s/m[ou]|[\dAlnz.\n_{}]|\$_=//gx;s/(.)(?{$*=''})/('
%2?'':"$0;").'pop;')x(ord($1)31).'$*'/gee;s/((.(\e\[.m)*|.)
; sub showpage {}
@P=split//,".URRUU\c8R";@d=split//,"\nrekcah xinU / lreP reh
@p{"r$p","u$p"}=(P,P);pipe"r$p","u$p";++$p;($q*=2)+=$f=!fork;map{
($p{$_})&6];$p{$_}=/ ^$P/ix?$P:close$_}keys%p}p;p;p;p;p;map{
close$_}%p;wait until$?;map{/^r/&&<$_>}%p;$_=$d[$q];sleep ra
In case you
#:: ::| ::| .. :||:: 0| .| ::||| .:|. :||
hadn't
open(Q,$0);while(<Q>){if(/^#(.*)$/){for(split('',$1)){$q=0;
/:.:/xg;s/:/../g;$Q=$_?length:$_;$q+=$q?$Q:$Q*20;}print chr(
noticed.
#.: ::||| .||| :|||| ::||| ||:: :|||| .:|
/;{}def/#{def}def/$_={/TimesBold exch selectfont}#/_{rmovet
;/q{exch}#/x ; {/J q #}#/.{/T q #}#{stringwidth}#{}#{}# 14 s
/;{}def/#{def}def/$_={/TimesBoldexchselectfont}#/_{ rmovet
;/q{exch}#/x ; {/J q #}#/.{/T q #}#{stringwidth}#{}#{}# 14 s
It's possible for the programmer
260 40 moveto 90 rotate ; %/}};$0='"\e[7m \e[0m"';@ARGV=spli
q(ThePerl). q(Journal) x 220 ; q ; 0 T putinterval exch 7 J
to make a mess of things.
; $_= q /m$ pop T($*!$"=!$ " )pop " * true% ? $ " $!" " !!
It's possible for Perl programmers
! charpath {!"""}pop $ pop{""!}pop ! neg{!#}pop 220 ! neg _{
to write messy programs.
charpath clip " pop 0 " moveto 6{!!}pop $_= 105{!!}pop {$ !
(In case you hadn't noticed.)
pop{dup dup $ ! " pop pop q{"}pop 22{dup show}repeat {"}pop
It's also possible for Perl
neg{!#! $ "}pop ! 8 .65 mul{$ # # $}pop ! neg{"}pop _ pop{"
programmers to write extremely
" { $ " ! ! ! $ " ! !" "#" #"!"""""! #" " # "m/;@ARGV=(@AR
clean, concise, and beautiful programs.
0 "%};s/m[ou]|[\dAlnz.\n_{}]|\$_=//gx;s/(.)(?{$*=''})/('
%2?'':"$0;").'pop;')x(ord($1)31).'$*'/gee;s/((.(\e\[.m)*|.)
; sub showpage {} fact that it's possible to write
The very
@P=split//,".URRUU\c8R";@d=split//,"\nrekcah xinU / lreP reh
messy programs in Perl is also what
@p{"r$p","u$p"}=(P,P);pipe"r$p","u$p";++$p;($q*=2)+=$f=!fork;map{
makes it possible to write programs
($p{$_})&6];$p{$_}=/ ^$P/ix?$P:close$_}keys%p}p;p;p;p;p;map{
that are cleaner in Perl than they
close$_}%p;wait until$?;map{/^r/&&<$_>}%p;$_=$d[$q];sleep ra
could ever be in a language that
#:: ::| ::| .. :||:: 0| .| ::||| .:|. :||
attempts to enforce cleanliness.
open(Q,$0);while(<Q>){if(/^#(.*)$/){for(split('',$1)){$q=0;
/:.:/xg;s/:/../g;$Q=$_?length:$_;$q+=$q?$Q:$Q*20;}print chr(
#.: ::||| .||| :|||| ::||| ||:: :|||| .:| Larry Wall
/;{}def/#{def}def/$_={/TimesBold exch selectfont}#/_{rmovet
;/q{exch}#/x ; {/J q #}#/.{/T q #}#{stringwidth}#{}#{}# 14 s
/;{}def/#{def}def/$_={/TimesBoldexchselectfont}#/_{ rmovet
;/q{exch}#/x ; {/J q #}#/.{/T q #}#{stringwidth}#{}#{}# 14 s
It's possible for the programmer
260 40 moveto 90 rotate ; %/}};$0='"\e[7m \e[0m"';@ARGV=spli
q(ThePerl). q(Journal) x 220 ; q ; 0 T putinterval exch 7 J
to make a mess of things.
; $_= q /m$ pop T($*!$"=!$ " )pop " * true% ? $ " $!" " !!
It's possible for Perl programmers
! charpath {!"""}pop $ pop{""!}pop ! neg{!#}pop 220 ! neg _{
to write messy programs.
charpath clip " pop 0 " moveto 6{!!}pop $_= 105{!!}pop {$ !
(In case you hadn't noticed.)
pop{dup dup $ ! " pop pop q{"}pop 22{dup show}repeat {"}pop
It's also possible for Perl
neg{!#! $ "}pop ! 8 .65 mul{$ # # $}pop ! neg{"}pop _ pop{"
programmers to write extremely
" { $ " ! ! ! $ " ! !" "#" #"!"""""! #" " # "m/;@ARGV=(@AR
clean, concise, and beautiful programs.
0 "%};s/m[ou]|[\dAlnz.\n_{}]|\$_=//gx;s/(.)(?{$*=''})/('
%2?'':"$0;").'pop;')x(ord($1)31).'$*'/gee;s/((.(\e\[.m)*|.)
; sub showpage {} fact that it's possible to write
The very
@P=split//,".URRUU\c8R";@d=split//,"\nrekcah xinU / lreP reh
messy programs in Perl is also what
@p{"r$p","u$p"}=(P,P);pipe"r$p","u$p";++$p;($q*=2)+=$f=!fork;map{
makes it possible to write programs
($p{$_})&6];$p{$_}=/ ^$P/ix?$P:close$_}keys%p}p;p;p;p;p;map{
that are cleaner in Perl than they
close$_}%p;wait until$?;map{/^r/&&<$_>}%p;$_=$d[$q];sleep ra
could ever be in a language that
#:: ::| ::| .. :||:: 0| .| ::||| .:|. :||
attempts to enforce cleanliness.
open(Q,$0);while(<Q>){if(/^#(.*)$/){for(split('',$1)){$q=0;
/:.:/xg;s/:/../g;$Q=$_?length:$_;$q+=$q?$Q:$Q*20;}print chr(
#.: ::||| .||| :|||| ::||| ||:: :|||| .:| Larry Wall
/;{}def/#{def}def/$_={/TimesBold exch selectfont}#/_{rmovet
;/q{exch}#/x ; {/J q #}#/.{/T q #}#{stringwidth}#{}#{}# 14 s
Disclaimer
<<Your favourite language>> is probably very nice
too
Every language makes different tradeoffs with
readability
This is (mainly) about Perl's
&$%@!
Sigils...
Hungarian Notation
$one
@many
%dictionary
Constructing Strings
In a VBlike syntax
"First: " + first + " Last: " + last +
vbCrLf + "Age: " + age
Constructing Strings
In Perl, with interpolation
"First: $first Last: $last\nAge: $age"
Constructing Strings
In Perl, with interpolation
"First: ${first} Last: ${last}\nAge:
${age}"
More template-like
Constructing Strings
In Perl, with interpolation
"First: ${first} Last: ${last}\nAge:
${age}"
Don't like the “\n” ?
Constructing Strings
Perl has multiline strings
And HERE-DOCs.
my $x = <<“STRING”;
First: ${first} Last: ${last}
Age: ${age}
STRING
Constructing Strings
Embed quotes in other languages
“Is this \“readable\”?”
“Is this “”better“”?”
Constructing Strings
Embed quotes in Perl
'This is “readable”'
Constructing Strings
Embed quotes in Perl
'This is “readable”'
“This isn't too bad either”
Constructing Strings
Embed quotes in Perl
'This is “readable”'
“This isn't too bad either”
q{ And isn't this “cool”? }
Constructing String Lists
my @list = (
“one”, “two”, “three” “,
... d'oh!
Constructing String Lists
my @list = qw(
one two three
four five six
);
qw() separated lists are easier to write at
least...
There's more than one way to do it
Conditionals
if ( $age < 18 ) { ...
if ( ! $age < 18 ) { ...
Conditionals
if ( $age < 18 ) { ...
unless ( $age < 18 ) { ...
Conditionals
if ( $age < 18 ) { ...
unless ( $age < 18 ) { ...
print “Over 18s only”
if $age < 18;
Conditionals
if ( $age < 18 ) { ...
unless ( $age < 18 ) { ...
print “Over 18s only”
if $age < 18;
print “Over 18s only”
unless $age >= 18;
Synonyms
Functionality?
Readability
Booleans
or
||
Booleans
or
||
Both mean same thing...
But have different precedence
'or' has lowest precedence of any operator
Booleans
<<any expression>> or <<fail>>;
Booleans
<<any expression>> or <<fail>>;
open my $FILEHANDLE,
'<', # for reading
$filename
or die
“Couldn't open ${filename}: $!”;
The unspeakable horror... regexes
Regexes
Not just Perl
Perl just handles them very well
Regexes
How do you break up a string?
Regexes
How do you break up a string?
Hack at it with INSTR()
Regexes
How do you break up a string?
Hack at it with INSTR()
Regexes
Regexes
How do you break up a string?
Hack at it with INSTR()
Regexes
Parser
Parse::RecDescent, HOP::Parser
Regexes
How do you break up a string?
Hack at it with INSTR()
Regexes
Parser
Parse::RecDescent, HOP::Parser
Data structure parser
XML (RSS/XPath etc.), MIME, iCal etc.
Regexes
How do you break up a string?
Regexes often hit the sweet spot...
...but they can get ugly when they're not the right
tool for the job
Regexes
Perl regexes are builtin
No need to
Compile(),
.Excecute(),
iterate through MatchCollection objects...
Regexes
Perl regexes are builtin
my ($first, $last) =
$name =~ /(\w+) (\w+)/;
Regexes
Perl regexes are builtin
my ($first, $last) =
$name =~ /(\w+) (\w+)/;
Other languages use strings:
“(\\w+) (\\w+)”
“\”\\w+\””
Regexes
Perl regexes are builtin
my ($first, $last) =
$name =~ /(\w+) (\w+)/;
Other languages use strings
“(\\w+) (\\w+)”
“\”\\w+\””
All Perl's quoting goodness
$url =~ s{^http://} {};
Regexes
Complex regexes are hard to read?
Regexes
Complex regexes are hard to read?
Comment!
$_ =~ m/^ # anchor at beginning of line
The\ quick\ (\w+)\ fox # fox adjective
\ (\w+)\ over # fox action verb
\ the\ (\w+) dog # dog adjective
(?: # whitespace-trimmed comment:
\s* \# \s* # whitespace and comment
(.*?) # captured comment text;
# (non-greedy!)
\s* # any trailing whitespace
)? # this is all optional
$ # end of line anchor
/x; # allow whitespace
Regexes
Named capture in 5.10
/(?<first>\w+) (?<last>\w+)/
Data Structures
Data Structures
Perl is:
Dynamic
expressionbased
Data Structures
Perl is:
Dynamic
expressionbased
Can declare most datastructures trivially at runtime.
Data Structures
Declare most datastructures trivially at runtime.
my $person = {
name => {
first => 'Fred',
last => 'Bloggs',
},
age => 12,
hobbies => [qw/
origami
windsurfing
/],
};
Data Structures
http://igoro.com/archive/7-tricks-to-simplify-your-programs-with-linq/#Tip1
C# with Linq
int[] a = Enumerable.Repeat
(-1, 10).ToArray();
int[] b = Enumerable.Range
(0, 10).ToArray()
Data Structures
http://igoro.com/archive/7-tricks-to-simplify-your-programs-with-linq/#Tip1
C# with Linq
int[] a = Enumerable.Repeat
(-1, 10).ToArray();
int[] b = Enumerable.Range
(0, 10).ToArray()
“Elegant”
Data Structures
http://igoro.com/archive/7-tricks-to-simplify-your-programs-with-linq/#Tip1
C# with Linq
int[] a = Enumerable.Repeat
(-1, 10).ToArray();
int[] b = Enumerable.Range
(0, 10).ToArray()
“Elegant”
Perl:
my @a = (-1) x 10;
my @b = (0..10);
Data Structures
http://igoro.com/archive/7-tricks-to-simplify-your-programs-with-linq/#Tip1
C# with Linq is elegant compared to:
int[10] b;
for (i=0; i<10; i++) {
b[i] = i;
}
Data Structures
http://igoro.com/archive/7-tricks-to-simplify-your-programs-with-linq/#Tip1
C# with Linq is elegant compared to:
int[10] b;
for (i=0; i<10; i++) {
b[i] = i;
}
This is really the functional vs. imperative debate
Functional Programming
Perl is not a functional programming language
Borrows some functional features
Functional Programming
Filter
@recent = grep {
$_->sent > ($today – ONE_DAY)
}
@emails;
Functional Programming
Transform
@full_names = map {
“$_->{first} $_->{last”
}
@people;
Functional Programming
A handful of other functions...
sort
join
Functional Programming
...and modules
use List::Util 'sum';
print sum(1..10);
Functional Programming
...and first class functions
sub double { return 2 * shift }
sub triple { return 3 * shift }
my %dispatch = (
double => \&double,
triple => \&triple,
);
my $result =
$dispatch{$command}->( $input );
Functional Programming
...including anonymous functions
my %dispatch = (
double => sub { 2 * shift },
triple => sub { 3 * shift },
)
Functional Programming
...and syntactic sugar
my @doubled = map { 2 * $_ } @nums;
First class functions
Enable metaprogramming
(OK, there's eval too... if you really need it)
First class functions
Typical cached subroutine
sub my_query {
my ($self, %params) = @_;
my $cache = $self>get_cache;
my $key = $self>get_key( %params );
my $result;
return $result if $result = $cache>get($key);
$result = $self>expensive_operation(%params);
# additional processing
$cache>set($key, $result, 20);
return $result;
}
First class functions
Typical cached subroutine
sub my_query {
my ($self, %params) = @_;
my $result
= $self>expensive_operation(%params);
# additional processing
return $result;
}
First class functions
Turn this second into the first
my $cached_query =
cache(\&query, %params);
Optionally, install it in the symbol table
*query = $cached_query;
Or add syntactic sugar!
sub my_query :Cached(time=>20) {
my $result = $self->expensive_operation;
# additional processing
return $result;
}
Working hard so you don't have to
Caching module
Attribute::Cached Unreleased
but see Memoize
package table hackery
(manual, but see Class::MOP)
Attribute parsing (using Attribute::Handlers)
Surprising fact
Perl programmers are (at best) obsessive
about syntax and readable code
Moose
Møøse
Built on scary crack (Class::MOP)
http://moose.perl.org/
http://www.iinteractive.com/moose/
Møøse
package Point;
use Moose;
# automatically turns on strict and warnings
has 'x' => (is => 'rw', isa => 'Int');
has 'y' => (is => 'rw', isa => 'Int');
sub clear {
my $self = shift;
$self->x(0);
$self->y(0);
}
Møøse
package Point3D;
use Moose;
extends 'Point';
has 'z' => (is => 'rw', isa => 'Int');
after 'clear' => sub {
my $self = shift;
$self->z(0);
};
Møøse
Not just syntactic sugar
(Post)modern OO
composition with roles
Møøse - example
HTTP request class
package Request;
use Moose;
use Moose::Util::TypeConstraints;
use HTTP::Headers ();
use Params::Coerce ();
use URI ();
has 'base' => (is => 'rw', isa => 'Uri', coerce => 1);
has 'uri' => (is => 'rw', isa => 'Uri', coerce => 1);
has 'method' => (is => 'rw', isa => 'Str');
has 'protocol' => (is => 'rw', isa => 'Protocol');
has 'headers' => (
is => 'rw',
isa => 'Header',
coerce => 1,
default => sub { HTTP::Headers->new }
);
Møøse - example
Hey! Types!
subtype 'Header'
=> as 'Object'
=> where { $_->isa('HTTP::Headers') };
subtype 'Protocol'
=> as Str
=> where { /^HTTP\/[0-9]\.[0-9]$/ };
subtype 'Uri'
=> as 'Object'
=> where { $_->isa('URI') };
Møøse - example
Coercions
working to make using the code easier
coerce 'Uri'
=> from 'Object'
=> via { $_->isa('URI')
? $_
: Params::Coerce::coerce( 'URI', $_ ) }
=> from 'Str'
=> via { URI->new( $_, 'http' ) };
Thank you
References
Pictures
perl.com/pub/a/1999/03/pm.html
“Larry Wall” by Michael McCracken
flickr.com/photos/michaelmccracken/540924868/
perl.com/pub/a/2004/01/16/regexps.html
Obfus (BooK, mjd, Les Peters)
igoro.com/archive/7trickstosimplifyyourprograms
withlinq/
“Donald Duck” (Disney)
moose.perl.org/
“Screwdrivers” by ladyheart
morguefile.com/archive/?display=134240&
blog.timbunce.org/2008/03/08/perlmyths/
“Horror Masks” by xenia
morguefile.com/archive/?display=93245&
“Swimming Duck" by Yael Lewenstein
flickr.com/photos/yaellebel
“Moose” by steve took it
flickr.com/photos/stevewall/290510690/
Get documents about "