Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

Elegant way to return true or nothing from a subroutine?

by Anonymous Monk
on Oct 10, 2006 at 01:24 UTC ( [id://577299]=perlquestion: print w/replies, xml ) Need Help??

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I want my boolean functions/methods to return true (1) or nothing (not zero or undef, nothing, as in "return;") like the Perl built-ins do. If the code just uses built-ins, it's no big deal:

sub foo { retrun shift->{age} == shift; }

The == op will return 1 if they're equal, nothing if they're not. But what if I'm calling someone else's code for the return value? What's the cleanest way to ensure I get that same kind of return value (1 or nothing)?

sub foo { return 1 if shift->{some_obj}->some_method; return; }

Is there a better way of doing this?

Replies are listed 'Best First'.
Re: Elegant way to return true or nothing from a subroutine?
by ysth (Canon) on Oct 10, 2006 at 02:10 UTC
    The builtins you seem to be referring to do not return nothing; they return a special false value that is "" in string context and 0 in numeric context (without warning the way "" would). This is very different from nothing:
    $ perl -w sub nothing { return; } sub something { return 0 == 1; } my @foo; push @foo, nothing(); print "foo has " . @foo . " elements after pushing nothing.\n"; push @foo, something(); print "foo has " . @foo . " element after pushing something.\n"; __END__ foo has 0 elements after pushing nothing. foo has 1 element after pushing something.
    (return; with no arguments does indeed return an empty list in list context, but undef in scalar context, which is very different from the usual false value.)

    The easiest way is to use the not-not operator; given your example:

    sub foo { return !! shift->{some_obj}->some_method; }
    Some people prefer:
    sub foo { return ( shift->{some_obj}->some_method ) ? 1 : 0; }
    and I can see an argument being made for having the false return value be either 0 or "", not both. But just using !! is convenient.

    If you actually do want nothing for false in a list context, do

    sub foo { return ( shift->{some_obj}->some_method ) ? 1 : (); }
    or
    sub foo { return shift->{some_obj}->some_method || (); }
    if true values other than 1 are permissable.
Re: Elegant way to return true or nothing from a subroutine?
by BrowserUk (Patriarch) on Oct 10, 2006 at 01:51 UTC

    If you want to cater for being called in a list context, I'd use

    sub foo { return !!shift->{some_obj}->some_method() || (); }

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Elegant way to return true or nothing from a subroutine?
by GrandFather (Saint) on Oct 10, 2006 at 01:37 UTC
    sub foo { return !! shift->{some_obj}->some_method; }

    or even:

    sub foo { !! shift->{some_obj}->some_method; }

    DWIM is Perl's answer to Gödel
      What does the !! mean? I thought it would be not not (in other words, true..)
        Ignoring non-integer values for brevity, the not not transformation maps 0 to 0 and everything else to 1:
        my @nums = (-2 .. 2); for my $num (@nums) { printf "!!%2d => %d\n", $num, !!$num; }
        gives
        !!-2 => 1 !!-1 => 1 !! 0 => 0 !! 1 => 1 !! 2 => 1
Re: Elegant way to return true or nothing from a subroutine?
by jasonk (Parson) on Oct 10, 2006 at 12:30 UTC

    return; does not return "nothing", as the documentation clearly states:

           return EXPR
           return  Returns from a subroutine, "eval", or "do FILE" with the value
                   given in EXPR.  Evaluation of EXPR may be in list, scalar, or
                   void context, depending on how the return value will be used,
                   and the context may vary from one execution to the next (see
                   "wantarray").  If no EXPR is given, returns an empty list in
                   list context, the undefined value in scalar context, and (of
                   course) nothing at all in a void context.                        
    

    So the equivalent to simply return; is return wantarray ? () : undef.


    We're not surrounded, we're in a target-rich environment!
      jasonk,
      Actually, the documentation clearly states it does return nothing provided the sub was called in a void context. Unfortunately there isn't a clear way to say:
      return defined(wantarray) ? wantarray ? () : undef : NOTHING;

      Cheers - L~R

        As fortunately, this never matters, because by definition nobody gets to look at the return value in void context.
Re: Elegant way to return true or nothing from a subroutine?
by chargrill (Parson) on Oct 10, 2006 at 01:32 UTC

    Does this fit what you're looking for?

    sub foo { return shift->{some_obj}->some_method ? 1 : undef; }


    --chargrill
    s**lil*; $*=join'',sort split q**; s;.*;grr; &&s+(.(.)).+$2$1+; $; = qq-$_-;s,.*,ahc,;$,.=chop for split q,,,reverse;print for($,,$;,$*,$/)

      undef isn't the same as "nothing":

      #!/usr/bin/perl -w use strict; sub ret_undef { return undef } sub ret_nothing { return; } print ret_nothing(), "\n"; print ret_undef(), "\n"; my @foo = ret_nothing(); print "Elements in foo: ", scalar @foo, "\n"; print @foo; my @bar = ret_undef(); print "Elements in bar: ", scalar @bar, "\n"; print @bar;

        Are you sure? Consider:

        use strict; use warnings; use Data::Dump::Streamer; my $value = undef; print !!$value; my $nothing = nothing (); my $retNothing = retNothing (); my $retUndef = retUndef (); my $retFalse = retFalse (); my $retFalse2 = -retFalse (); Dump (\$nothing); Dump (\$retNothing); Dump (\$retUndef); Dump (\$retFalse); Dump (\$retFalse2); sub nothing { } sub retNothing { return; } sub retUndef { return undef; } sub retFalse { return 1 == 0; }

        Prints:

        $SCALAR1 = \do { my $v = undef }; $SCALAR1 = \do { my $v = undef }; $SCALAR1 = \do { my $v = undef }; $SCALAR1 = \do { my $v = '' }; $SCALAR1 = \do { my $v = 0 };

        Updated to add two false cases

        and in list context :)

        ... my @nothing = nothing (); my @retNothing = retNothing (); my @retUndef = retUndef (); my @retFalse = retFalse (); my @retFalse2 = -retFalse (); Dump (\@nothing); Dump (\@retNothing); Dump (\@retUndef); Dump (\@retFalse); Dump (\@retFalse2); ...

        Prints:

        $ARRAY1 = []; $ARRAY1 = []; $ARRAY1 = [ undef ]; $ARRAY1 = [ '' ]; $ARRAY1 = [ 0 ];

        DWIM is Perl's answer to Gödel
Re: Elegant way to return true or nothing from a subroutine?
by CountZero (Bishop) on Oct 10, 2006 at 05:48 UTC
    Do you care to explain why you want false to be nothing rather than zero or undef? For ages these values have served us well, but perhaps you have found a good reason why this is not a good idea anymore.

    CountZero

    "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law

Re: Elegant way to return true or nothing from a subroutine?
by Anonymous Monk on Oct 10, 2006 at 07:34 UTC
    The only way to return 'nothing' from a subroutine is to call it in void context. Otherwise, it will always return something. An argument less return in scalar context will return the undefined value. In list context, such a thing will return an empty list (which some may call 'nothing'). Buildins often return the empty string in scalar context, a false but defined value, that doesn't have a length when printed. But it certainly isn't 'nothing'.
Re: Elegant way to return true or nothing from a subroutine?
by pdcawley (Hermit) on Oct 10, 2006 at 11:00 UTC
    How about:
    sub foo { shift->{some_obj}->some_method && 1 || return }
    Personally I think your attachment to requiring that all your true values be 1 is vaguely silly. A better solution would seem to be:
    sub foo { shift->{some_obj}->some_method || return }
    Wah! Guess who's been programming in ruby recently. I initially wrote those as sub foo; ...; end

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others goofing around in the Monastery: (6)
As of 2024-04-19 08:16 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found