catch me if you can: sugary exception handling in perl

47
YAPC EU 2009 = ASH BERLIN ‹ %DEVEL DECLARE / SCOPE UPPER ‹ eASH BERLIN aASH BERLIN ½ MST < FLORIAN RAGWITZ / VINCENT PIT £MARK FOWLER / THE O’REILLY CAMEL EXCEPTION HANDLING IN PERL if you can catch me Tuesday, 11 August 2009

Upload: ash-berlin

Post on 06-May-2015

3.332 views

Category:

Technology


1 download

DESCRIPTION

Exception handling in perl is currenlty far from perfect. eval leaves a lot to be desired. Lots of {dark,cpan} code is rife with pottential code that could interfere with $@ TryCatch (on CPAN now) fixes this through the magic of Devel::Declare. Breifly address what's wrong with eval, what I/we'd like, and then finally how it was done using Devel::Declare

TRANSCRIPT

Page 1: Catch Me If You Can: Sugary Exception Handling in Perl

YAPC EU 2009 = ASH BERLIN ‹ %DEVEL DECLARE / SCOPE UPPER ‹eASH BERLIN aASH BERLIN ½ MST < FLORIAN RAGWITZ / VINCENT PIT

£MARK FOWLER / THE O’REILLY CAMEL

EXCEPTION HANDLING IN PERL

if you cancatch me

Tuesday, 11 August 2009

Page 2: Catch Me If You Can: Sugary Exception Handling in Perl

Catch Me If You Can:Sugary exception handling with TryCatch.pm

Ash BerlinYAPC::EU 2009 – Lison

A.K.A The please don’t sue me Title

Tuesday, 11 August 2009

Page 3: Catch Me If You Can: Sugary Exception Handling in Perl

Perl Sucks!(and what to do about it)

Image courtesy of Mark Fowler

YAPC::EU 2007 – Vienna

Tuesday, 11 August 2009

Page 4: Catch Me If You Can: Sugary Exception Handling in Perl

Perl Sucks?

• Of course it does, it’s software

• Installing Modules is hard

• Perl programs are just scripts

• Its Exception handling is hateful

Tuesday, 11 August 2009

Page 5: Catch Me If You Can: Sugary Exception Handling in Perl

eval {};sucks

Tuesday, 11 August 2009

Page 6: Catch Me If You Can: Sugary Exception Handling in Perl

eval {};sucks

Tuesday, 11 August 2009

Page 7: Catch Me If You Can: Sugary Exception Handling in Perl

eval sucks

• Sucky syntax

• Easy to get (subtly) wrong.

• return doesn’t work as expected

• eval BLOCK vs eval EXPR

• $@ is global

Tuesday, 11 August 2009

Page 8: Catch Me If You Can: Sugary Exception Handling in Perl

“But Perl already has exception handling”

Lots of Exception::* and Error::* modules

Tuesday, 11 August 2009

Page 9: Catch Me If You Can: Sugary Exception Handling in Perl

None of them Perfect

• Some are just an exception framework

• Good; doesn’t solve catching problem

• Catching errors shouldn’t be hard

Tuesday, 11 August 2009

Page 10: Catch Me If You Can: Sugary Exception Handling in Perl

I want the Moon on a Stick

Tuesday, 11 August 2009

Page 11: Catch Me If You Can: Sugary Exception Handling in Perl

I want the Moon on a Stick

Tuesday, 11 August 2009

Page 12: Catch Me If You Can: Sugary Exception Handling in Perl

Exceptions in JavaScript

try { someCallThatDies();}catch (e if e instanceof Error) {}catch (f if f.length < 10) {}catch (g) { /* otherwise */ }

Tuesday, 11 August 2009

Page 13: Catch Me If You Can: Sugary Exception Handling in Perl

The same in Perl

if (blessed($@) && $@->isa(‘Error’)) { my $e = $@;}elsif (len($@) < 10 ) { my $f = $@; }elsif ($@) { my $g = $@;}

eval { some_call_that_dies();};

Tuesday, 11 August 2009

Page 14: Catch Me If You Can: Sugary Exception Handling in Perl

The same in PerlDone properly

{ local $@; eval { some_call_that_dies(); }; if (my $_e = $@) { if (blessed($_e) && $_e->isa(‘Error’)) { my $e = $_e; } elsif (len($_e) < 10 ) { my $f = $_e; } else { my $g = $_e; } }}

Tuesday, 11 August 2009

Page 15: Catch Me If You Can: Sugary Exception Handling in Perl

That’s a lot to write every time

Not very DRY

Tuesday, 11 August 2009

Page 16: Catch Me If You Can: Sugary Exception Handling in Perl

Using Error.pm

Looking good so far…

use Error qw(:try);try { some_call_that_dies(); }catch Error with { my $e = shift;}

Tuesday, 11 August 2009

Page 17: Catch Me If You Can: Sugary Exception Handling in Perl

Using Error.pm

otherwise { my $f = shift; if (length($f) < 10) { } else { my $g = $f; }} Less good :(

use Error qw(:try);try { some_call_that_dies(); }catch Error with { my $e = shift;}

Tuesday, 11 August 2009

Page 18: Catch Me If You Can: Sugary Exception Handling in Perl

Problems with Error.pm

• (Not to single it out as bad)

• Its Exception Object class

• AND try/catch implementations

• sub {} closures are slow

• Speed for error free path is important

Tuesday, 11 August 2009

Page 19: Catch Me If You Can: Sugary Exception Handling in Perl

TryCatch.pm

use TryCatch;try { some_call_that_dies();}catch (Error $e) {}catch ($f where {length < 10}) {}catch ($g) {} # otherwise

Tuesday, 11 August 2009

Page 20: Catch Me If You Can: Sugary Exception Handling in Perl

TryCatch syntax

• try must be followed by a block

• Followed by zero or more catch clauses

• catch may be followed by a signature

• catch must also be followed by a block

Tuesday, 11 August 2009

Page 21: Catch Me If You Can: Sugary Exception Handling in Perl

Try syntax

• try keyword

• Followed by a block

• That was easy :)

Tuesday, 11 August 2009

Page 22: Catch Me If You Can: Sugary Exception Handling in Perl

Catch syntax

• catch keyword

• Followed by an optional signature:

(MyError $e where { } )

• Followed by a block.

Tuesday, 11 August 2009

Page 23: Catch Me If You Can: Sugary Exception Handling in Perl

Catch Sig syntax

• MyError is any valid Moose type constraint

• Optional

• Uses MooseX::Types for preference

• Else falls back to Moose’s string parsing

• Never quoted, always bare

• Example:

Str|ArrayRef[MyError]

(MyError $e where { } )

Tuesday, 11 August 2009

Page 24: Catch Me If You Can: Sugary Exception Handling in Perl

Catch Sig syntax

• $e is the variable name for the error

• Will be created as “my $e” in the block

• A variable name is required

(MyError $e where { } )

Tuesday, 11 August 2009

Page 25: Catch Me If You Can: Sugary Exception Handling in Perl

Catch Sig syntax

• Constraint (not type constraint)

• $_ is the error being tested.

• Much like grep or map, return truthy value

• PPI used to just get ‘everything in {}’

(MyError $e where { } )

Tuesday, 11 August 2009

Page 26: Catch Me If You Can: Sugary Exception Handling in Perl

Syntax Notes

• try can be nested as deep as you like

• You can use return to exit the sub.

• No finally. Yet. It’s on my TODO

Tuesday, 11 August 2009

Page 27: Catch Me If You Can: Sugary Exception Handling in Perl

TryCatch examplesub foo {

try { die MyError->new($_[0]) if $_[1] eq “class”; die $_[0] if $_[1] eq “plain”;

return “value”;}catch (MyError $e) { }catch ($e where { /No Cheese!/ }) { }catch ($e) { } # otherwise

}

Tuesday, 11 August 2009

Page 28: Catch Me If You Can: Sugary Exception Handling in Perl

TryCatch examplesub foo {

try { die MyError->new($_[0]) if $_[1] eq “class”; die $_[0] if $_[1] eq “plain”;

return “value”;}catch (MyError $e) { }catch ($e where { /No Cheese!/ }) { }catch ($e) { } # otherwise

}

This will return a value from foo, not just the try/eval

i.e. use return natually

Tuesday, 11 August 2009

Page 29: Catch Me If You Can: Sugary Exception Handling in Perl

sub foo {try { die MyError->new($_[0]) if $_[1] eq “class”; die $_[0] if $_[1] eq “plain”;

return “value”;}catch (MyError $e) { }catch ($e where { /No Cheese!/ }) { }catch ($e) { } # otherwise

}

TryCatch exampleMoose type constraints

handle the “is this a blessed object” and similar checks

Tuesday, 11 August 2009

Page 30: Catch Me If You Can: Sugary Exception Handling in Perl

TryCatch exampleIf this wasn’t here, and the plain error was thrown, it

would get re-thrown.

sub foo {try { die MyError->new($_[0]) if $_[1] eq “class”; die $_[0] if $_[1] eq “plain”;

return “value”;}catch (MyError $e) { }catch ($e where { /No Cheese!/ }) { }catch ($e) { } # otherwise

}

Tuesday, 11 August 2009

Page 31: Catch Me If You Can: Sugary Exception Handling in Perl

ImplementationHere Be (anthropomorphic) Dragons

xkcd.com

Tuesday, 11 August 2009

Page 32: Catch Me If You Can: Sugary Exception Handling in Perl

Source Filters

• Have to look through the entire source

• And only change the bits they want.

• Perl is notoriously hard to parse

• Can cause odd bugs:

Tuesday, 11 August 2009

Page 33: Catch Me If You Can: Sugary Exception Handling in Perl

package ShootMeInTheHead;

use Moose;use Switch;

sub foo {  my ($variable) = @_;  return $variable + 1;}sub bar {  my ($variable) = @_;  return $variab1e + 1;}}

Source Filters

Global symbol "$variab1e" requires explicit package name at line 18.

Tuesday, 11 August 2009

Page 34: Catch Me If You Can: Sugary Exception Handling in Perl

package ShootMeInTheHead;

use Moose;use Switch;

sub foo {  my ($variable) = @_;  return $variable + 1;}sub bar {  my ($variable) = @_;  return $variab1e + 1;}}

Source Filters

Global symbol "$variab1e" requires explicit package name at line 18.

# load switch statement

Tuesday, 11 August 2009

Page 35: Catch Me If You Can: Sugary Exception Handling in Perl

package ShootMeInTheHead;

use Moose;use Switch;

sub foo {  my ($variable) = @_;  return $variable + 1;}sub bar {  my ($variable) = @_;  return $variab1e + 1;}}

Source Filters

Global symbol "$variab1e" requires explicit package name at line 14.

# load switch statement

Tuesday, 11 August 2009

Page 36: Catch Me If You Can: Sugary Exception Handling in Perl

Devel::Declare

• Lets you change the source Perl is about to compile

• Like a source filter

• But far less fragile.

• Key-hole source filter effect.

Tuesday, 11 August 2009

Page 37: Catch Me If You Can: Sugary Exception Handling in Perl

• When perl parses

catch ($e) { my $foo = …

Using Devel::Declare

• Sees catch as a OP_CONST

Tuesday, 11 August 2009

Page 38: Catch Me If You Can: Sugary Exception Handling in Perl

• When perl parses

catch ($e) { my $foo = …

Using Devel::Declare

• Calls PL_check[OP_CONST]

Tuesday, 11 August 2009

Page 39: Catch Me If You Can: Sugary Exception Handling in Perl

• When perl parses

catch ($e) { my $foo = …

Using Devel::Declare

• Calls PL_check[OP_CONST]

• Devel::Declare hooks this

• And calls back into perl code

Tuesday, 11 August 2009

Page 40: Catch Me If You Can: Sugary Exception Handling in Perl

• When perl parses

catch ($e) { my $foo = …

Using Devel::Declare

• Calls PL_check[OP_CONST]

• Devel::Declare lets us change this into…

catch; { if (my $e = $@) { my $foo = …

Tuesday, 11 August 2009

Page 41: Catch Me If You Can: Sugary Exception Handling in Perl

Using Devel::Declare

• TryCatch doesn’t quite produce that code

• But it shows how things work

• Also uses B::Hooks::OP::{Check,PPaddr} to solve the return problem

Tuesday, 11 August 2009

Page 42: Catch Me If You Can: Sugary Exception Handling in Perl

The return problem

• Simple:

sub foo { eval { return $val }; 1}

• Would be nice if it returned from foo

• vincent++ # Scope::Upper

• unwind HERE, @values;

Tuesday, 11 August 2009

Page 43: Catch Me If You Can: Sugary Exception Handling in Perl

The return problem

• Typing return would be better than unwind

• Install an extra PL_check hook on OP_RETURN

• And install a custom op handler

• Makes return inside try behave like unwind

Tuesday, 11 August 2009

Page 44: Catch Me If You Can: Sugary Exception Handling in Perl

In short, lots of scary XS.

Tuesday, 11 August 2009

Page 45: Catch Me If You Can: Sugary Exception Handling in Perl

use TryCatch;

try { some_call_that_dies();}catch (Error $e) {}catch ($f where {length < 10}) {}catch ($g) {} # otherwise

Tuesday, 11 August 2009

Page 46: Catch Me If You Can: Sugary Exception Handling in Perl

use TryCatch;

try ;{ local $@; eval { some_call_that_dies(); }; $TryCatch::Error = $@; }if ($TryCatch::Error) { if (TryCatch->check_tc('Error')){ my $e = $TryCatch::Error; } elsif (do {local $_ = $TryCatch::Error; length($_) < 10 }) { my $f = $TryCatch::Error; } elsif (1){ my $g = $TryCatch::Error; } # otherwise else { $@ = $TryCatch::Error; die } }

Tuesday, 11 August 2009

Page 47: Catch Me If You Can: Sugary Exception Handling in Perl

hu∙bris |ˈhjuːbrɪs|nounexcessive pride or self-confidence.

• (in Greek tragedy) excessive pride toward or defiance of the gods, leading to nemesis.

DERIVATIVEShu∙bris∙tic |(h)yoōˈbristik| |(h)juˈbrɪstɪk| |-ˈbrɪstɪk| adjective

ORIGIN Greek.

Questions?<[email protected]>

Ash Berlin

Tuesday, 11 August 2009