Perl in the 21st Century


Eric Wilhelm
http://scratchcomputing.com/
1 / 108

aka
2 / 108

Hair and Yak again.
A hacker's tale.
3 / 108

Still No Flying Car
4 / 108

Good, Cheap, Fast
...
Pick any two
       one.
5 / 108

Still No Silver Bullet
6 / 108

I read the history
so you don't have to.
7 / 108

You read the history
so I don't have to.
8 / 108

<zombie>
BRAINZ!
</zombie>
9 / 108

Standing on the Shoulders of 1975
10 / 108

"I'd like to keep it to CORE if at all possible."

11 / 108

"I'd rather start with the simplest possible things right now."

12 / 108

survival of the good-enoughest
13 / 108

Design
of by
Distributed
Systems
14 / 108

Dude,
Silver Bullets
vs
Zombies.
 
FAIL!
15 / 108

Perl is Dead.
Long live Perl.
16 / 108

Timeline
 
Me, CPAN, etc

(Number of authors by first dist date.)

17 / 108

2000
18 / 108

Mugs were thrown.

This was a perfectly controlled tantrum. It was amazing to see.
I was thinking,
"Should I get up and throw mugs too?"

19 / 108

"Eventually the subversions are taking as long as the original
Perl 1 - Perl 2 thing,

...
20 / 108

...

but that's because they are actually accomplishing just as much."

21 / 108

"Sometimes you have make negative progress in order to go forward in
the long run."
22 / 108

"Someone has to throw the tea into the Boston Harbor."
23 / 108

"... plus it's time to steal

all the good
ideas we can

from those other languages
that developed in the last decade."

24 / 108

"In the meantime, we are not abandoning Perl 5 anytime soon.

...
25 / 108

...

we fully expect, given the history of Perl 4, that five years from now a lot of people will still be using Perl 5."

26 / 108

MJD's Report:

"The other big problem is thirteen years of backward compatibility
...
We can't add a new built-in function because it might break old code. It's extremely difficult to remove even the most bizarre and little-used old features, because it might break old code."

"... 5.8 will be the final release of Perl 5 ..."

27 / 108

whatever
28 / 108

Fast-Forward
 
2002
 
I get a camel book.
29 / 108

Architectural
Engineering
30 / 108

Architectural:

  • Design for:
    • Function
    • Usability
    • Efficiency
31 / 108

Engineering:

  • Design for:
    • Resilience
    • Safety
    • Economy
32 / 108

Perl gets the job done.
33 / 108

The job gets bigger.
34 / 108

Perl gets the bigger job done.
35 / 108

The bigger job gets bigger.
36 / 108

Suddenly, I'm a "programmer".
aka
"Developer"
aka
"Software Engineerer"
37 / 108

CAD::Drawing
CAD::Calc
Math::Vec
Math::Geometry::Planar::Offset
38 / 108

But before I got here:
39 / 108

Perl 5 EOL
40 / 108

that just leaves
the
CPAN
41 / 108

Some thoughts:
42 / 108

Software Design

  • cost
  • efficiency
  • effectiveness
43 / 108

API Design

  • concision
  • extensibility
44 / 108

tools for
managing complexity
  • functions
  • lambda
  • exceptions
  • modules
  • objects
45 / 108

API Design is an Art
46 / 108

good artists always
kill their babies
47 / 108

YAGNI
vs
WAGNW?
48 / 108

Second
System
Syndrome
49 / 108

CPAN
killer app
50 / 108

CPAN
app killer
51 / 108

CPAN
"the great experiment"
52 / 108

good
vs
bad
vs
     ugly
53 / 108

"I'm still learning the libraries."
54 / 108

1994-10-17
50 Core Modules in 5.0.0

AnyDBM_File AutoLoader AutoSplit Benchmark Carp Cwd DB_File DynaLoader English Env Exporter ExtUtils::MakeMaker Fcntl File::Basename File::CheckTree File::Find FileHandle GDBM_File Getopt::Long Getopt::Std I18N::Collate IPC::Open2 IPC::Open3 Math::BigFloat Math::BigInt Math::Complex NDBM_File Net::Ping ODBM_File POSIX SDBM_File Search::Dict Shell Socket Sys::Hostname Sys::Syslog Term::Cap Term::Complete Test::Harness Text::Abbrev Text::ParseWords Text::Soundex Text::Tabs TieHash Time::Local integer less sigtrap strict subs

55 / 108

2000-03-22
5.6.0 added these 166

B B::Asmdata B::Assembler B::Bblock B::Bytecode B::C B::CC B::Debug B::Deparse B::Disassembler B::Lint B::Showlex B::Stackobj B::Stash B::Terse B::Xref ByteLoader CGI CGI::Apache CGI::Carp CGI::Cookie CGI::Fast CGI::Pretty CGI::Push CGI::Switch CPAN CPAN::FirstTime CPAN::Nox Carp::Heavy Class::Struct Config DB Data::Dumper Devel::DProf Devel::Peek Devel::SelfStubber DirHandle Dumpvalue Exporter::Heavy ExtUtils::Command ExtUtils::Embed ExtUtils::Install ExtUtils::Installed ExtUtils::Liblist ExtUtils::MM_Cygwin ExtUtils::MM_OS2 ExtUtils::MM_Unix ExtUtils::MM_VMS ExtUtils::MM_Win32 ExtUtils::Manifest ExtUtils::Mkbootstrap ExtUtils::Mksymlists ExtUtils::Packlist ExtUtils::XSSymSet ExtUtils::testlib Fatal File::Compare File::Copy File::DosGlob File::Glob File::Path File::Spec File::Spec::Functions File::Spec::Mac File::Spec::OS2 File::Spec::Unix File::Spec::VMS File::Spec::Win32 File::stat FileCache FindBin IO IO::Dir IO::File IO::Handle IO::Pipe IO::Poll IO::Seekable IO::Select IO::Socket IO::Socket::INET IO::Socket::UNIX IPC::Msg IPC::Semaphore IPC::SysV JNI JPL::AutoLoader JPL::Class JPL::Compile Math::Trig Net::hostent Net::netent Net::protoent Net::servent O OS2::DLL OS2::ExtAttr OS2::PrfDB OS2::Process OS2::REXX Opcode Pod::Checker Pod::Find Pod::Functions Pod::Html Pod::InputObjects Pod::Man Pod::ParseUtils Pod::Parser Pod::Plainer Pod::Select Pod::Text Pod::Text::Color Pod::Text::Termcap Pod::Usage Safe SelectSaver SelfLoader Symbol Term::ANSIColor Term::ReadLine Test Text::Wrap Thread Thread::Queue Thread::Semaphore Thread::Signal Thread::Specific Tie::Array Tie::Handle Tie::Hash Tie::RefHash Tie::Scalar Tie::SubstrHash Time::gmtime Time::localtime Time::tm UNIVERSAL User::grent User::pwent VMS::DCLsym VMS::Filespec VMS::Stdio XSLoader attributes attrs autouse base blib bytes charnames constant diagnostics fields filetest lib locale open ops overload re utf8 vars vmsish warnings warnings::register

56 / 108

2002-07-19
5.8.0 added these 119

Attribute::Handlers B::Concise CGI::Util Class::ISA Devel::PPPort Digest Digest::MD5 Encode Encode::Alias Encode::Byte Encode::CJKConstants Encode::CN Encode::CN::HZ Encode::Config Encode::EBCDIC Encode::Encoder Encode::Encoding Encode::Guess Encode::JP Encode::JP::H2Z Encode::JP::JIS7 Encode::KR Encode::KR::2022_KR Encode::MIME::Header Encode::Symbol Encode::TW Encode::Unicode ExtUtils::Command::MM ExtUtils::Constant ExtUtils::Liblist::Kid ExtUtils::MM ExtUtils::MM_Any ExtUtils::MM_BeOS ExtUtils::MM_DOS ExtUtils::MM_MacOS ExtUtils::MM_NW5 ExtUtils::MM_UWIN ExtUtils::MM_Win95 ExtUtils::MY File::Spec::Cygwin File::Spec::Epoc File::Temp Filter::Simple Filter::Util::Call Hash::Util I18N::LangTags I18N::LangTags::List I18N::Langinfo List::Util Locale::Constants Locale::Country Locale::Currency Locale::Language Locale::Maketext Locale::Script MIME::Base64 MIME::QuotedPrint Math::BigFloat::Trace Math::BigInt::Calc Math::BigInt::Trace Math::BigRat Memoize Memoize::AnyDBM_File Memoize::Expire Memoize::ExpireFile Memoize::ExpireTest Memoize::NDBM_File Memoize::SDBM_File Memoize::Storable NEXT Net::Cmd Net::Config Net::Domain Net::FTP Net::FTP::A Net::FTP::E Net::FTP::I Net::FTP::L Net::FTP::dataconn Net::NNTP Net::Netrc Net::POP3 Net::SMTP Net::Time PerlIO PerlIO::encoding PerlIO::scalar PerlIO::via PerlIO::via::QuotedPrint Pod::LaTeX Pod::ParseLink Pod::Text::Overstrike Scalar::Util Storable Switch Test::Builder Test::Harness::Assert Test::Harness::Iterator Test::Harness::Straps Test::More Test::Simple Text::Balanced Tie::File Tie::Memoize Time::HiRes Unicode Unicode::Collate Unicode::Normalize Unicode::UCD XS::APItest XS::Typemap bigint bignum bigrat encoding if sort threads threads::shared

57 / 108

2006-01-31
5.8.8 had 45 more

DBM_Filter DBM_Filter::compress DBM_Filter::encode DBM_Filter::int32 DBM_Filter::null DBM_Filter::utf8 DCLsym Digest::base Digest::file Encode::MIME::Header::ISO_2022_JP Encode::Unicode::UTF7 Errno ExtUtils::Constant::Base ExtUtils::Constant::Utils ExtUtils::Constant::XS ExtUtils::MM_AIX ExtUtils::MM_QNX ExtUtils::MM_VOS ExtUtils::MakeMaker::Config ExtUtils::MakeMaker::bytes ExtUtils::MakeMaker::vmsish Filespec I18N::LangTags::Detect Locale::Maketext::Guts Locale::Maketext::GutsLoader Math::BigInt::CalcEmu Pod::Perldoc Pod::Perldoc::BaseTo Pod::Perldoc::GetOptsOO Pod::Perldoc::ToChecker Pod::Perldoc::ToMan Pod::Perldoc::ToNroff Pod::Perldoc::ToPod Pod::Perldoc::ToRtf Pod::Perldoc::ToText Pod::Perldoc::ToTk Pod::Perldoc::ToXml Pod::PlainText Stdio Test::Builder::Module Test::Builder::Tester Test::Builder::Tester::Color Test::Harness::Point Win32 XSSymSet

58 / 108

2007-12-18
5.10.0 has 200 more

Archive::Extract Archive::Tar Archive::Tar::Constant Archive::Tar::File CPAN::API::HOWTO CPAN::Debug CPAN::DeferedCode CPAN::HandleConfig CPAN::Kwalify CPAN::Queue CPAN::Tarzip CPAN::Version CPANPLUS CPANPLUS::Backend CPANPLUS::Backend::RV CPANPLUS::Config CPANPLUS::Configure CPANPLUS::Configure::Setup CPANPLUS::Dist CPANPLUS::Dist::Base CPANPLUS::Dist::Build CPANPLUS::Dist::Build::Constants CPANPLUS::Dist::MM CPANPLUS::Dist::Sample CPANPLUS::Error CPANPLUS::Internals CPANPLUS::Internals::Constants CPANPLUS::Internals::Constants::Report CPANPLUS::Internals::Extract CPANPLUS::Internals::Fetch CPANPLUS::Internals::Report CPANPLUS::Internals::Search CPANPLUS::Internals::Source CPANPLUS::Internals::Utils CPANPLUS::Internals::Utils::Autoflush CPANPLUS::Module CPANPLUS::Module::Author CPANPLUS::Module::Author::Fake CPANPLUS::Module::Checksums CPANPLUS::Module::Fake CPANPLUS::Module::Signature CPANPLUS::Selfupdate CPANPLUS::Shell CPANPLUS::Shell::Classic CPANPLUS::Shell::Default CPANPLUS::Shell::Default::Plugins::CustomSource CPANPLUS::Shell::Default::Plugins::Remote CPANPLUS::Shell::Default::Plugins::Source CPANPLUS::inc Compress::Raw::Zlib Compress::Zlib Config::Extensions DCLsym Devel::InnerPackage Digest::SHA Digest::file Encode::GSM0338 Encode::MIME::Header::ISO_2022_JP Encode::MIME::Name ExtUtils::CBuilder ExtUtils::CBuilder::Base ExtUtils::CBuilder::Platform::Unix ExtUtils::CBuilder::Platform::VMS ExtUtils::CBuilder::Platform::Windows ExtUtils::CBuilder::Platform::aix ExtUtils::CBuilder::Platform::cygwin ExtUtils::CBuilder::Platform::darwin ExtUtils::CBuilder::Platform::dec_osf ExtUtils::CBuilder::Platform::os2 ExtUtils::Constant::Base ExtUtils::Constant::ProxySubs ExtUtils::Constant::Utils ExtUtils::Constant::XS ExtUtils::MM_AIX ExtUtils::MM_QNX ExtUtils::MM_VOS ExtUtils::MakeMaker::Config ExtUtils::ParseXS File::Fetch File::GlobMapper Hash::Util::FieldHash IO::Compress::Adapter::Deflate IO::Compress::Adapter::Identity IO::Compress::Base IO::Compress::Base::Common IO::Compress::Deflate IO::Compress::Gzip IO::Compress::Gzip::Constants IO::Compress::RawDeflate IO::Compress::Zip IO::Compress::Zip::Constants IO::Compress::Zlib::Constants IO::Compress::Zlib::Extra IO::Uncompress::Adapter::Identity IO::Uncompress::Adapter::Inflate IO::Uncompress::AnyInflate IO::Uncompress::AnyUncompress IO::Uncompress::Base IO::Uncompress::Gunzip IO::Uncompress::Inflate IO::Uncompress::RawInflate IO::Uncompress::Unzip IO::Zlib IPC::Cmd Locale::Maketext::Simple Log::Message Log::Message::Config Log::Message::Handlers Log::Message::Item Log::Message::Simple Math::BigInt::FastCalc Module::Build Module::Build::Base Module::Build::Compat Module::Build::Config Module::Build::ConfigData Module::Build::Cookbook Module::Build::Dumper Module::Build::ModuleInfo Module::Build::Notes Module::Build::PPMMaker Module::Build::Platform::Amiga Module::Build::Platform::Default Module::Build::Platform::EBCDIC Module::Build::Platform::MPEiX Module::Build::Platform::MacOS Module::Build::Platform::RiscOS Module::Build::Platform::Unix Module::Build::Platform::VMS Module::Build::Platform::VOS Module::Build::Platform::Windows Module::Build::Platform::aix Module::Build::Platform::cygwin Module::Build::Platform::darwin Module::Build::Platform::os2 Module::Build::PodParser Module::Build::Version Module::Build::YAML Module::CoreList Module::Load Module::Load::Conditional Module::Loaded Module::Pluggable Module::Pluggable::Object Moped::Msg Object::Accessor Package::Constants Params::Check Pod::Escapes Pod::Simple Pod::Simple::BlackBox Pod::Simple::Checker Pod::Simple::Debug Pod::Simple::DumpAsText Pod::Simple::DumpAsXML Pod::Simple::HTML Pod::Simple::HTMLBatch Pod::Simple::HTMLLegacy Pod::Simple::LinkSection Pod::Simple::Methody Pod::Simple::Progress Pod::Simple::PullParser Pod::Simple::PullParserEndToken Pod::Simple::PullParserStartToken Pod::Simple::PullParserTextToken Pod::Simple::PullParserToken Pod::Simple::RTF Pod::Simple::Search Pod::Simple::SimpleTree Pod::Simple::Text Pod::Simple::TextContent Pod::Simple::TiedOutFH Pod::Simple::Transcode Pod::Simple::TranscodeDumb Pod::Simple::TranscodeSmart Pod::Simple::XMLOutStream Stdio Sys::Syslog::win32::Win32 Term::UI Term::UI::History Test::Builder::Module Test::Builder::Tester Test::Builder::Tester::Color Test::Harness::Point Test::Harness::Results Test::Harness::Util Tie::Hash::NamedCapture Tie::StdHandle Time::Piece Time::Piece::Seconds Time::Seconds Win32 Win32API::File Win32API::File::ExtUtils::Myconst2perl Win32CORE XSSymSet encoding::warnings feature mro version

586
59 / 108

2009
60 / 108

21 years old
61 / 108

still living at home
62 / 108

Deadbeat
63 / 108

Generation Y?
Echo Boomer?
Trophy Kid?
64 / 108

But...
Do you still wear
your baby clothes?
65 / 108

Just take Perl 5
Maybe more like 30/40-something.
Mullet,
Skynyrd,
15th year at the plant.
66 / 108

Putting
little brother 6
through college?
67 / 108

GetOpt

Getopt::Long
Getopt::Auto
Getopt::Plus
Getopt::EUCLID
Getopt::Lucid
Scriptalicious
Getopt::MooseX
68 / 108

Getopt::AsDocumented
 
=head1 Usage

  your-program [options] inputfile outputfile

=head1 Options

=over

=item -i, --input-file FILENAME

=for positional
=for isa File::Fu::File

Input file name.

=item -o, --output-file FILENAME

=for positional
=for isa File::Fu::File

Output file name.
69 / 108

=item -x, --explode

Self-destruct.

DEFAULT: NO

=item -v, --verbose

Emit extra information. 

=item -q, --quiet, --no-verbose

Emit no extra information.

=item --version

Display version number.

=item -h, --help

=for help show this help message

Show help and options.

=back

=cut
70 / 108

$VERSION = v42.7.9; use warnings; use strict;

use Getopt::AsDocumented;
sub main {
  my $o = Getopt::AsDocumented->process(\@ARGV) or
    return;

  die "explode!\n" if($o->explode);
  warn "yay!\n" if($o->verbose);

  my @lines = $o->input->read;
}

main(@ARGV) unless caller;
71 / 108

Usage

        basic [options] inputfile outputfile

Options

-i, --input-file FILENAME

Input file name.

-o, --output-file FILENAME

Output file name.

...
72 / 108

Fear of Death?
73 / 108

Fear of Fear of Death?
eval {
  ...
  local $SIG{__DIE__} = '__DEFAULT__';
}
???
74 / 108

Fear of Fear of Fear?

 > My question is: why not
eval {require Foo}
 But what if:
$SIG{__DIE__} = sub {
  print STDERR "Die! What?\n"; exit 0
};
75 / 108

Fear of Rope?

BEGIN {
  open(STDERR, '>', $0);
}
use 42;
76 / 108

We know
where you go
when you die.
77 / 108

Where do you go when you don't?
return $rows == 0 ? "0E0" : $rows;
hell
my $v = $dbh->do(...);
return -1 unless(defined($v));
if($v == 0) {...}
78 / 108

File::Spec
File::Temp
File::Basename
File::Copy
File::Which
FindBin
79 / 108

my $file = File::Spec->catfile($dir, $name);
my $base = File::Basename::basename($file);

my $file = $dir + $name;
my $base = $file->file;
80 / 108

my @files;
File::Find::find({
  no_chdir => 1,
  wanted => sub {
    if(-d $_ and m/\.svn/) {
      $File::Find::prune = 1;
      return;
    }
    (-d $_) and return;
    m/\.pm$/ or return;
    push(@files, $File::Find::name);
  }}, $dir);

my @files = $dir->find(sub {
  return shift->prune
    if(-d and $_->end =~ m/^\.svn$/);
  $_->is_file and m/\.pm$/;
});
81 / 108

my $which     = File::Fu->which('which');

my $temp_dir  = File::Fu->temp_dir;

my $temp_file = File::Fu->temp_file;

my $here      = File::Fu->THIS_FILE;

my $there     = File::Fu->program_name;

my $ifh       = $file->open;

my $ofh       = $file->open('>');

my $contents  = $file->read;

$file->write($content);

$file->copy($destination);
82 / 108

Closed vs Open API
  • non-blocking
  • iterators
  • lazy lists
83 / 108

But we don't have
API versioning.
 
         base2?
          DBI2?
     Exporter2?
Module::Build2?
         CPANPLUSER?
84 / 108

premature ossification
standards are fun
85 / 108

Another Theory
86 / 108

Some Yaks were shaved.
87 / 108

Module::Build

  • Pure Perl
  • Extensible
  • Configurable
  • Different
88 / 108

META.yml

  • requires/provides
  • dynamic_config: 0
  • configure_requires
  • MYMETA.yml
89 / 108

Irrational Stop Energy:

"I happen to really like MakeMaker.
Makefiles actually work,
unlike Module::Build.
But that's a religious argument."

— A recent comment on the 6PAN.
90 / 108

"Build issues are being covered. QA.
Notice that that's perl-qa -- we're hoping that we can back-apply some of the QA things we develop in Perl 6 back to Perl 5."

— Larry in Camel Lot #6
91 / 108

Historical accident
vs
Intelligent design
92 / 108

More Yaks
93 / 108

Tap::Harness

  • runs in parallel
  • s/perl/exec/
  • formalizes TAP
aside: runs aground on Getopt::Long
94 / 108

More Yaks

PAR
Module::ScanDeps

ExtUtils::MacMaker
Devel::TraceDeps
integrators wanted
95 / 108

Fear of Objects?

Objects
are too
Complicated
96 / 108

Code without
Objects
is too
Complicated
97 / 108

Accessors

sub foo {
  my $self = shift;
  return $self->{foo} unless(@_);
  return $self->{foo} = shift;
}

...

warn $thing->foo;
$thing->foo(7);
(A moose to shave.)
98 / 108

Values

warn $foo;
$foo = 7;
99 / 108

Faster and more obvious

sub foo { shift->{foo} }
sub set_foo { $_[0]->{foo} = $_[1] }

...

warn $thing->foo;
$thing->set_foo(7);
100 / 108

More elegant

sub foo :lvalue { shift->{foo} }

...

warn $thing->foo;
$thing->foo = 7;
101 / 108

Poorly implemented.
Debugger broken?
No validation.
No Encapsulation.
102 / 108

Source munging?
sub foo { shift->{foo} }
sub set_foo :sets(foo) { $_[0]->{foo} = $_[1] }

...

warn $thing->foo;
$thing->foo = 7;
                # becomes:
                $thing->set_foo(7);
103 / 108

MetaMetaMetaMOP

(intermission)
104 / 108

List::oo
Method::Signatures?
and-also-isms
use lambda;
my $subref = λ{...};
105 / 108

#!/usr/bin/perl

use warnings;
use strict;
use Time::Piece;
use Date::Piece;
use File::Fu;
use lambda;
use List::oo qw(L);
use YAML::XS;

sub main {
  ...
}
main(@ARGV) unless caller;
106 / 108

sub main {
  my $d = YAML::XS::LoadFile('/tmp/report.yml');

  my %dyear; my %nyear;
  foreach my $dist (keys (%$d)) {
    my $years = L(@{$d->{$dist}})->
      map(λ{localtime($_->{mtime})->date->year});
    ($dyear{$_} ||= 0)++ for(@$years);
    ($nyear{$years->min} ||= 0)++;
  }

  my $rep = λ{
    my $h = shift;
    L(sort keys %$h)->map(λ{join("\t", $_, $h->{$_})})->ipush('')->join("\n")
  };

  File::Fu->file('/tmp/dist-counts.tsv')->write($rep->(\%dyear));
  File::Fu->file('/tmp/ship-counts.tsv')->write($rep->(\%nyear));
}
107 / 108

use modern;
sub main {
  my $opt = getopt(@_) or return;

  for my $line ($opt->input->open->lines) {
    print $line->chomped->
      split(/\t/)->map{$_+2}->join(','), "\n";
  }
}
108 / 108