There are some situations where one will commonly get a return value of true, false, or undef and each needs to be handled distinctly. Two examples off the top of my head are fork and wantarray. I'm wondering what idiom monks use for this situation since I've never quite been satisfied with my own ways.
For fork, I used to write this most often:
my $pid = fork; die "can't fork: $!" if ! defined $pid; if ( $pid ) { # parent } else { # child }
With Perl 5.10, this gets a little easier.
use 5.010; my $pid = fork // die "Can't fork: $!"; if ...
That's one less statement, and it reads neatly "fork or die".
use 5.010; given ( fork ) { when ( undef ) { die "Can't fork: $!"; } when ( !$_ ) { # child } default { # parent my $child_pid = $_; } }
One thing I don't like about using given/when for this is that it's hard to rearrange the clauses. I can't say "when ($_)" because it's always true, even when $_ is false. That's a problem common to this situation, however. You can't just take "false" as false, since it might also be undef. That is, one always has to check defined before falsehood.
About all this has going for it is I only create a $pid variable where I need it (in the parent). This seems clumsy for fork, but it might make more sense for wantarray.
use 5.010; given ( wantarray ) { when ( undef ) { return; # void context } when ( !$_ ) { return 'scalar context'; } default { return qw( list context ); } }
That's good if I really need a block for each condition to take different actions in the different situations. On the other hand, if all I'm doing is selecting a return value base on context, the ternary seems ready-made.
return wantarray ? qw( list context ) : defined wantarray ? 'scalar context';
Maybe I should have a function hide the mess and make a call to it be my idiom.
return tfu( wantarray, true => sub { 'true' }, false => sub { 'false' }, undef => sub { 'undef' }, ); sub tfu { my $value = shift @_; my %todo_for = @_; return $value ? $todo_for{ true }->() : defined $value ? $todo_for{ false }->() : $todo_for{ undef }->(); }
I can put my "clauses" in any order, and the sub will figure it out. I can pile into the sub defaults and validation and whatever else. That's a far cry from a convenient idiom, however.
At this point, I think I've just thought about this too much. I wonder what others think.
|
|---|