Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

An idiom for selecting true, false, or undef.

by kyle (Abbot)
on Mar 17, 2009 at 16:11 UTC ( [id://751234]=perlmeditation: print w/replies, xml ) Need Help??

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.

Replies are listed 'Best First'.
Re: An idiom for selecting true, false, or undef.
by perrin (Chancellor) on Mar 17, 2009 at 16:16 UTC
    Your first way seems totally fine to me. You could use the "condition or die" approach that people use for file operations:
    defined $pid or die "failed to fork: $!";
Re: An idiom for selecting true, false, or undef.
by Bloodnok (Vicar) on Mar 17, 2009 at 16:53 UTC
    Since I discovered it (solely thanks to this community), I tend to (probably over) use autodie in cases similar to the fork example - relying on perl/the OS to make a sensible report (which, in most cases, they do) - resulting in code such as ...
    use autodie; if (my $pid = fork) { # Some parenting wouldn't go amiss } else { # Do some child stuff }

    As for the simple, value based wantarray example, I quite like your tfu approach...

    A user level that continues to overstate my experience :-))
Re: An idiom for selecting true, false, or undef.
by ELISHEVA (Prior) on Mar 17, 2009 at 21:05 UTC

    When I need to distinguish between the three, I generally go with

    if (!defined($bSomething)) { ... } elsif ($bSomething) { ... } else { ... }

    and sometimes

    my $x = defined($bSomething) ? $bSomething : $DEFAULT_VALUE; if ($x) { ... } else { ... }

    The verbosity doesn't really bother me; it works with older versions of Perl; and it's easy to read.

    Best, beth

Re: An idiom for selecting true, false, or undef.
by xdg (Monsignor) on Mar 17, 2009 at 16:43 UTC

    It may not be a good idiom, but usually I only check wantarray for a true value, and just return a scalar value in either scalar or void context and just let Perl throw it away if unused. I think that's probably reasonable for anything for which the typical case is to return one or more values and I don't see much point in adding the void case just to be pedantic.

    For fork, the last time I did it, I used a three-part if/elsif/else for clarity.

    -xdg

    Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

Re: An idiom for selecting true, false, or undef.
by JavaFan (Canon) on Mar 17, 2009 at 20:35 UTC
    I seldomly need an idiom to distinguish between all three - in most cases, I'm either interested in "true or false" or "defined or not defined". In the rare cases, the idiom I use depends whether I consider all cases equal or not.

    fork is an example where not all cases are equal. undef signals an error condition, while true/false but defined happen equally often. So, I typically write:

    my $pid = fork // die "fork: $!"; unless ($pid) { ... child stuff ... exit; } ... parent stuff ... wait;
    Note that the above code doesn't have an else clause. That's intentional.

    In the rare case all three cases are equally important, I might write:

    given (EXPR) { when (!defined) {...} when (!$_) {...} default {...} }
    or an if/elsif/else construct. But that's so rare, I can't even remember what I did last time. In the case of wantarray, wantarray being not defined is the exceptional case - if I'm interested in it, I most likely use it for flow control, bypassing expensive calculations.
Re: An idiom for selecting true, false, or undef.
by zentara (Archbishop) on Mar 17, 2009 at 16:29 UTC
        Oh planetscape, you are so helpful. If only your name was planetescape, we might have a future together. :-) and maybe you would be talking like the girl from Ipanema. ;-)

        Now, I don't want you and almut fighting over me. :-)


        I'm not really a human, but I play one on earth My Petition to the Great Cosmic Conciousness
Re: An idiom for selecting true, false, or undef.
by sundialsvc4 (Abbot) on Mar 18, 2009 at 16:10 UTC

    My best counsel on this point is:  

    SWYMOD:   Say What You Mean Or die

    • If truth-or-falsehood is known and is an appropriate response, your code should return one of those values.
    • If “nothing” is an appropriate thing to return, your code may return undef. But, by the same logic that says (in SQL) that “NULL is not False; it is the absence of a value,” you should not return “the absence of a value” when what-you-mean is “I do have a value, and that value is False.”
    • If the situation that you have just encountered “cannot happen, but it just did,” then you should IMHO never return anything. You should die, or better yet, use one of the carp functions such as croak.

    In this way, when you do “return something,” what you return is the most meaningful and descriptive response that you could have returned. And if not, you do not return at all... thus forming a useful social-contract that, if your function does return a value, that value can be relied-upon without further testing of return-values and so forth. Exception-handling blocks are efficient and cheap. (Obviously they cannot be used in all cases, e.g. for historical reasons.)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://751234]
Approved by moritz
Front-paged by Arunbear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others browsing the Monastery: (1)
As of 2024-04-24 17:00 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found