in reply to Re^7: STDERR in Test Results
in thread STDERR in Test Results
I don't like dieing at any point in my programs and I look down on code which does that and forces me to try/catch/eval each of its calls instead of checking the error code that each function, IMO, should return (with reasonable exceptions of course).
I avoided to express my opinions as I respect the particular opinion of those particular Monks who were in favour of die as error signaling and decided to keep quiet and contemplate on their points and see if I can change my opinion.
Well, I haven't mainly because of reasons of style. I still return error codes or error hashes with code+message. I started with C, and it shows, and I think I will die with C.
But! I found a compromise: I now consider a die to be an exception (as in, e.g. C++/Java) and it does not look as the "nutter's nuclear option" as it did. And I may even experiment dieing with an Exception object (read on before telling me that that's possible already :)):
use Storable; use MIME::Base64; use Data::Dumper; eval { die encode_base64(freeze({errorcode => 12, errormess => 'you have die +d'})); }; print "error caught: ".Dumper(thaw(decode_base64($@))) if $@;
But at that exact point of my epiphany I learned that die can throw ANYTHING (about time!), so:
use Data::Dumper; eval { die {errorcode => 12, errormess => 'you have died'}; }; print "error caught: ".Dumper($@) if $@; # or even better eval { die bless {errorcode => 12, errormess => 'you have died'} => 'My::Exc +eption'; }; print "error caught2: ".$@->{errormess}."\n" if $@ and ref($@) eq 'My: +:Exception';
So, yes, I can view die as an exception and am prepared not to consider it antisocial, from now on. The only problem remaining is performance:
use Storable qw/freeze thaw/; use MIME::Base64; use Data::Dumper; use Benchmark qw/:all/; use strict; use warnings; sub die_bliako_way { die encode_base64(freeze({errorcode => 12, errormsg => 'you have die +d'})); } sub die_common_sense { die {errorcode => 12, errormsg => 'you have died'}; } sub die_common_sense_blessed { die bless {errorcode => 12, errormsg => 'you have died'} => 'My::Exc +eption'; } sub no_die { return {errorcode => 12, errormsg => 'you have died'}; } timethese(10_000_000, { 'die_bliako_way' => sub { eval { die_bliako_way }; if( $@ && exists(thaw(decode_base64($@))->{errorcode}) ){ } }, 'die_common_sense' => sub { eval { die_common_sense }; if( $@ && exists($@->{errorcode}) ){ } }, 'no_die' => sub { my $ret = no_die(); if( exists $ret->{errorcode} ){ } } });
Benchmark: timing 10000000 iterations of die_bliako_way, die_common_se +nse, die_common_sense_blessed, no_die... die_bliako_way: 56 wallclock secs (55.04 usr + 0.01 sys = 55.05 CPU) +@ 181653.04/s (n=10000000) die_common_sense: 5 wallclock secs ( 5.25 usr + 0.00 sys = 5.25 CPU +) @ 1904761.90/s (n=10000000) die_common_sense_blessed: 5 wallclock secs ( 5.36 usr + 0.00 sys = +5.36 CPU) @ 1865671.64/s (n=10000000) no_die: 5 wallclock secs ( 3.77 usr + 0.00 sys = 3.77 CPU) @ 26 +52519.89/s (n=10000000)
No contest there for no_die. But the test may be misleading because no_die() needs constant return status checking with an if exists. Whereas, as you show in the transactions example you provided, functions which die can skipp the individual checking and enclose them all in one big try{}catch{} block. Which is probably way faster. And I don't know which looks uglier: huge try{}catch{} blocks or endless if func() then else (actually I think the latter).
So, thanks for the food for thought you provided. I am much more inclined in using die now in subs especially the dieing with custom-made exception objects.
bw, bliako
|
|---|