http://www.perlmonks.org?node_id=1019361

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

I want to do some conditional math. Without going into extensive explaination, I can't use a condtional statement.

So I'm attempting this in sort of an APL-ish approach:

# conditionally add 250 to the result iif $temp > 100;
my $temp = 150;
my $r = 1000;
$r += 250 * ( $temp > 100 );


I was pleasantly surprised to see this actually work correctly on my linux Perl 5.8.8 box, $r is 1000 unless $temp > 100 then its 1250. Perfect!

But what I wonder (and have my doubts about) is, will this appoach also work on a arbitrary Perl/OS implementation? My doubt is that ( $temp > 100 ) will consistently evaluate to 0 or 1 (as it does in APL, making it function perfectly for cases like this)..

Thank You wise ones.

Replies are listed 'Best First'.
Re: Is this reliable?
by tobyink (Canon) on Feb 18, 2013 at 16:43 UTC

    Perl has some special constants that it returns as true and false in response to comparisons and some other boolean expressions. You can peek at the internals of these constants using Devel::Peek:

    $ perl -MDevel::Peek -e'Dump(1 < 2)' SV = PVNV(0xa1046e4) at 0xa102520 REFCNT = 2147483644 FLAGS = (PADTMP,IOK,NOK,POK,READONLY,pIOK,pNOK,pPOK) IV = 1 NV = 1 PV = 0xa1055d0 "1"\0 CUR = 1 LEN = 12 $ perl -MDevel::Peek -e'Dump(1 > 2)' SV = PVNV(0x947a6d0) at 0x9478510 REFCNT = 2147483647 FLAGS = (PADTMP,IOK,NOK,POK,READONLY,pIOK,pNOK,pPOK) IV = 0 NV = 0 PV = 0x947a6c8 ""\0 CUR = 0 LEN = 12

    Interesting observations:

    • Note the high REFCNT; this ensures that these constants are never destroyed by the garbage collector.

    • The PV shows you how these constants are stringified. True becomes "1" and false is the empty string.

    • The IV shows you how these constants are converted to integers. True becomes 1 and false is 0.

    • They're read-only...

      $ perl -e'$x = \(1 < 2); $$x++' Modification of a read-only value attempted at -e line 1.

    I'm not going to say that these constants are never going to change (never say never!) but it would probably break a lot of code if they did, so I think p5p would be pretty wary of changing this. The Enterprise operator (see perlsecret) relies on them numifying as 0 and 1.

    package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name
Re: Is this reliable?
by blue_cowdawg (Monsignor) on Feb 18, 2013 at 16:41 UTC
        But what I wonder (and have my doubts about) is, will this appoach also work on a arbitrary Perl/OS implementation? My doubt is that

    As far as I know the results of a comparative will always evaluate as a non-zero if true. That said I'd be more comfortable doing things this way:

    my $r = (temp> 100? 1000: 1250);
    That should eliminate any doubt of the matter.


    Peter L. Berghold -- Unix Professional
    Peter -at- Berghold -dot- Net; AOL IM redcowdawg Yahoo IM: blue_cowdawg

      Or even
          $r += ($temp > 100 ? 250 : 0);
      or
          $temp > 100 and $r += 250;

Re: Is this reliable?
by frozenwithjoy (Priest) on Feb 18, 2013 at 17:11 UTC
    My preference is to use the ternary operator (like others have shown) if you are setting $r once, but if I were updating $r in a loop, for example, based on the value of $temp, I'd probably just go with this:
    $r += 250 if $temp > 100;

    I find it very readable.

Re: Is this reliable?
by aitap (Curate) on Feb 18, 2013 at 16:49 UTC

    It should work reliably (but I couldn't find any links about it, besides Truth and Falsehood, Scalar values). You can force any true value to be 1 by adding !! before it. You can also use $r += $temp > 100 ? 250 : 0; if you are still in doubt.

    Update: as pointed out above, it usually works and should work further, but the ternary operator is safer.

    Sorry if my advice was wrong.
      Many thanks Monks (and a bow)- your knowledge of internals is awe-inspiriing, and in my case perhaps a bit of a consolation. For now based on your findings, I'll go with 0 and 1 will be my cast-value from bool to int.

      I also tried it with a regex and that ALSO yielded 0 and 1 (yay).

      I'd actually considered using ? : construct, and may end up with that, but I'm hoping I don't have to.

      Here my issue- I'm sort of allowing web users to *write psuedo-perl* , which I convert into actual Perl, then eval. I want to only yield them a very tiny subset of commands- mostly along the lines of doing math, or setting values on values in only one hash. So I didn't want to let them deviate too far even into conditionals. All of course for obvious security reasons..

      Thanks * 10 !

        Personally I'd get them to write an entirely different scripting language and then either write a parser/interpreter for that scripting language, or use an off the shelf one (like JE for Javascript).

        package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name
        Oh yeah, did something similar a few years ago and line input '<>' and Here-doc '<<' operators were the obvious trouble makers. Since I only allowed simple arithemtic constructs I could get by with regexes to police the code but I never trusted that completely.
        ... for obvious security reasons..

        Ah, the ever-reliable "Security Through Obscurity" strategy!

        You can try Safe for restricting string eval but remember that there is no warranty of 100% safety. A bug in Perl or in this module can lead to a security hole.
        Sorry if my advice was wrong.
Re: Is this reliable?
by LanX (Saint) on Feb 19, 2013 at 10:56 UTC
    Yes it's safe!

    A boolean will be interpreted as 1 or 0 in a numeric context!

    Cheers Rolf

      THanks to all. The security points are well taken under advisement. Luckily for me this is an internal site with only 3 users on whom I maintain a tight reign :) As always, well done all. Best wishes for a warm and productive Springtime 2013.