John M. Dlugosz has asked for the wisdom of the Perl Monks concerning the following question:

With regular boolean tests, you can use DeMorgan's identities and other manipulations to reverse the test. In Perl, you have if/unless pairs to reverse the sense of the test.

We have || returning the actual value of the first true thing, so we can easily apply a default if something is not specified, and // improves upon that.

But I want the opposite: If some value is undefined, I want to stop there and return undef from the function. Only if it's defined do I want to keep going and return the result of subsequent processing, such as another function call.

my $x= ...; return undef unless defined $x; return morefoo($x);
I can't help but find that annoying and ugly, as there should be a sleek way of writing it that's as nice as return $this // $that; given that so many such succinct things are indeed available. So what is a good idiom? I could certainly write the above as one statement but I still mention $x twice.

Replies are listed 'Best First'.
Re: What's the opposite of // (err) operator?
by GrandFather (Saint) on May 11, 2011 at 04:45 UTC

    maybe:

    my $x = (...) // return; return morefoo($x);
    True laziness is hard work
Re: What's the opposite of // (err) operator?
by Tux (Canon) on May 11, 2011 at 05:57 UTC

    If you want to explicitly return undef you rather not specify it and return the right thing in all contexts:

    defined $x or return; return morefoo ($x);

    In scalar context, that will return undef, in list context, that will return the empty list. If $x is defined, the context is propagated to morefoo.


    Enjoy, Have FUN! H.Merijn
      Nice. I always forget about the low-precidence variations. Combining that with GrandFather's reply gives:
      my $x= blahblah... err return; ... continue using $x
      That reads with the proper "flow" and connotations: if I find an undef after this computation, quit now.

      Now what version of Perl introduced err?

      later... Apparently not the one I'm using! The construct above gives an error, "missing operator before err?", but the syntax works with or so it's not the precedence, but rather it seems not to know what err means!

      The perldoc perlop (I'm reading for Perl 5.10.1 since that's what I'm using) has a section called “Logical or, Defined or, and Exclusive Or”, and it discusses the low-precedence or and xor but doesn't actually mention any kind of "defined or" keyword. How odd.

        Do not use the err keyword. It was introduced in the 5.9.x development series, and made available to all the 5.8.x builds by patches (maintained by me).

        The community however decided that err did not have enough good reasons to stay and was removed later on. That made me feel sad, but I am not the one that makes the final decision. The bottom line is that err, which was a special type of operator that could be overruled by a local function with the same name, is not available in 98% perl. Do not use it.


        Enjoy, Have FUN! H.Merijn

        There isn't one. But then again, you don't need one. A low-precedence variation would cause a needless assignment to be performed.

        my $x = EXPR // return; ... continue using $x
Re: What's the opposite of // (err) operator?
by BrowserUk (Patriarch) on May 11, 2011 at 06:27 UTC

    All these three perform the same way:

    #! perl -slw use strict; sub morefoo{ $_[0] * 3 } sub a { my $x = shift; return defined $x ? morefoo( $x ) : undef; } sub b { my $x; return defined( $x = shift ) ? morefoo( $x ) : undef; } sub c { return morefoo( shift // return undef ); } print "$_ :> ", a( $_ ) for undef, 0, 1 ; print "$_ :> ", b( $_ ) for undef, 0, 1 ; print "$_ :> ", c( $_ ) for undef, 0, 1 ; __END__ C:\test>junk93 Use of uninitialized value $_ in concatenation (.) or string at C:\tes +t\junk93.pl line 21. Use of uninitialized value in print at C:\test\junk93.pl line 21. :> 0 :> 0 1 :> 3 Use of uninitialized value $_ in concatenation (.) or string at C:\tes +t\junk93.pl line 23. Use of uninitialized value in print at C:\test\junk93.pl line 23. :> 0 :> 0 1 :> 3 Use of uninitialized value $_ in concatenation (.) or string at C:\tes +t\junk93.pl line 25. Use of uninitialized value in print at C:\test\junk93.pl line 25. :> 0 :> 0 1 :> 3

    The last is the 'cleanest', though less than intuitive.

    The problem with a defined-and construct is that you need to retain the tested value for use on the right-hand side of the construct.

    Unlike the defined-or where the defined value is the required result for the left-hand side; or you know it must be undef and so do not need to retain it for the right-hand side.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      On a tangent, your shebang line draws my attention. I remember -w from the distant past. I looked up -s and it parses switches, but this code doesn't use any. So, is this just something you always use for quick test scripts? I also read about -l but don't see what it would be used for. (And does it notice that the following character is not an octnum so it gangs the -w switch and leaves the argument blank?)
Re: What's the opposite of // (err) operator?
by thewebsi (Scribe) on May 11, 2011 at 05:01 UTC

    I think what you mean by "opposite", is that you want something that returns $this when $this // $that would normally return $that, and you want to do it in one line with only one mention of each of the 2 expressions:

    defined ( $this ) ? $that : undef

    defined ( $this ) && $that || undef

Re: What's the opposite of // (err) operator?
by anonymized user 468275 (Curate) on May 11, 2011 at 09:11 UTC
    The implication is that wittingly or unwittingly you want undef to be the only false value. I think that is the higher priority anomaly to address in your story. With Perl it is far more viable to enforce a regime of true=ok false=not ok and use boolean logic rather than testing for defined() or specific values, with some exceptions such as testing for the presence of keys/indexes in hashes/arrays or managing return codes from external programs or scripts. So in the given example I would expect to deal with it much more simply from where $x goes wrong e.g.:
    $x = ... or return;
    But if say $x == 0 is okay for continuing, then:
    defined( $x = ... ) or return;
    I can conceive of returning undef explicitly in some cases but if you are deviating too often from "statement or return" simplicity then it's your boolean logic management that really needs simplifying rather than addressing the symptoms in the form of more complex value logic.

    One world, one people

      No, I know to use Perl boolean rather than tests against actual values.

      In the case at hand, I really want undef to stop subsequent work on the value. It's more like a database NULL, rather than a value of 0 (or an empty string). Maybe both of those are allowed values that I want to operate on.

        Problem with that is that NULL ( =undef() ) lacks even quasi-tautology as a test for mechanistic failure. I'd be inclined to keep the return value strictly for that and use references or instance subvariables to pass the actual database values between routines.

        DBI (to the extent I use it) sticks to these basic principles. If another required module doesn't, I'd use inheritance into a fairly trivial class that performs the separation between value logic and mechanistic logic for any "misbehaving" methods, rather than look for a way to do that throughout my higher level code.

        One world, one people