Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Converting to boolean

by dragonchild (Archbishop)
on Jun 17, 2004 at 03:16 UTC ( [id://367515]=perlmeditation: print w/replies, xml ) Need Help??

If I have a value I want to convert to a boolean, I use $x = $x && 1. I've also seen $x = !! $x. Are these the only ones? Which one(s) do you use? Is there a difference?

------
We are the carpenters and bricklayers of the Information Age.

Then there are Damian modules.... *sigh* ... that's not about being less-lazy -- that's about being on some really good drugs -- you know, there is no spoon. - flyingmoose

I shouldn't have to say this, but any code, unless otherwise stated, is untested

Replies are listed 'Best First'.
Re: Converting to boolean
by Zaxo (Archbishop) on Jun 17, 2004 at 03:49 UTC

    There is also a variation on yours; $x &&= 1; and there is the corresponding pair on or; $x = $x || 0; $x ||= 0;. Update: Also trinary, $x = $x ? 1 : 0; and all sorts of variations on that, which have the advantage that truth and falsity are what you say they are.</Update>

    None of the basic three are equivalent. Here is a comparison:
    Expr Value Result Value Result
    $x = $x && 1; true 1 false unchanged
    $x = $x || 0; true unchanged false 0
    $x = !! $x; true1 false''
    But see diotalevi's fine reply for what !! actually returns. Context is everything!
    Only $x = !! $x; gives you what I think you want.

    But perl generally limps along just fine without any boolean type at all. See What is truth? (Curiosity corner).

    After Compline,
    Zaxo

Re: Converting to boolean
by diotalevi (Canon) on Jun 17, 2004 at 03:41 UTC

    An update ... though stuff like '=' assignments make this entirely less than obvious. Check these stats out.

    use Devel::Size 'total_size'; $ARY[ $_ ] = ? for 1 .. 1_000_000; print total_size( \ @ARY ) . "\n"; # Do this as a comparison of a sparse array $ARY_B[ 1_000_000 ] = 1; print total_size( \ @ARY_B );
    CodeSize
    sparse4,000,072
    undef16,194,340
    120,195,340
    \ undef20,194,352
    \ !120,194,377
    \ !!120,194,378
    \ 120,195,340
    ( 1 + $| )24,194,340
    \ ( 1 + $| )40,194,340
    !141,194,340
    !!142,194,340

    I use !! $x because the return value is one of the values PL_sv_yes or PL_sv_no both of which are a single scalar that is shared through the entire process, forever. It is somewhat like undef being shared everywhere. You can have a million return values from !! $x and have them take up no space or you can have a million 1's and every one takes up a whole SV's worth of memory.

    The choice is obvious.

Re: Converting to boolean
by Sidhekin (Priest) on Jun 17, 2004 at 03:50 UTC

    I use !!$x for this. Perl6 will give us ?$x, which ought to be clearer.

    If I wanted to store the boolean back into the same variable, I might prefer a mutator: $x &&= 1.

    However, there is a real difference:

    sidhekin@blackbox:~$ perl my ($x, $y) = (0, 0); $x = $x && 1; # or $x &&= 1; $y = !!$y; print "\$x: '$x'\n\$y: '$y'\n"; __END__ $x: '0' $y: '' sidhekin@blackbox:~$

    ... something to be aware of :-)

    print "Just another Perl ${\(trickster and hacker)},"
    The Sidhekin proves Sidhe did it!

Re: Converting to boolean
by davido (Cardinal) on Jun 17, 2004 at 04:32 UTC

    How about a tied scalar operating as a boolean?

    package Tie::MyBoolean; sub TIESCALAR { my($class, $value ) = @_; my $boolval = ( $value ) ? 1 : 0; return bless \$boolval, $class; } sub STORE { my $self = shift; ${$self} = ( shift ) ? 1 : 0; return ${$self}; } sub FETCH { my $self = shift; return ${$self}; } 1; package main; use strict; use warnings; tie my $bool, 'Tie::MyBoolean'; $bool = 100; print "$bool\n"; $bool = 0; print "$bool\n"; $bool = ! $bool; print "$bool\n";

    This has the characteristic of working a lot like $| (the autoflush special variable), which can only take on 0 or 1 as a value.


    Dave

Re: Converting to boolean
by hv (Prior) on Jun 17, 2004 at 14:19 UTC

    When I want clarity, or when I specifically want to avoid an undefined value, I tend to use the trinary operator:

    $bool = $x ? 1 : 0;

    When I want shortness I tend to use !!$x.

    When I'm comparing truthness of two expressions, I factor out one of the !s:

    if (!$x == !$y) { ... }

    Hugo

Re: Converting to boolean
by Roy Johnson (Monsignor) on Jun 17, 2004 at 14:40 UTC
    Nobody's mentioned $x != 0, which might be expected to work, but gets tripped up by the "0 but true" phenomenon, as does $x ^ ''. $x xor 0 should work, because xor is a logical op.

    Disclaimer: I've only got perl4 to test on.


    We're not really tightening our belts, it just feels that way because we're getting fatter.
      Incidental trick, there is not need to use "0 but true" since "0.0" has the exact same effect. (Note that the quotes matter.)

      I'm not sure how that would run under flea-bitten corpses of dead camels though. (Can you tell that I'm somewhat flabbergasted at your using a version of Perl that is about a decade out of date?)
        Rest assured that I don't normally live in such third-world Perl environs. I'm only here for a week, and it hasn't been until today that I've needed Perl, so it hasn't been as horrible as it sounded.

        We're not really tightening our belts, it just feels that way because we're getting fatter.
Re: Converting to boolean
by dvergin (Monsignor) on Jun 17, 2004 at 15:53 UTC
    My first reaction was: Why would one want do do that? Any value will act as a boolean if used in a boolean context.

    But I note that this question has been posed and answered by experienced monks who give every indication of taking this matter quite seriously.

    So clearly I'm missing something. I've never been aware of a need for this. Could someone offer a few cases where converting to such a "boolean" value is better than simply using the variable as-is in a boolean context.

    ------------------------------------------------------------
    "Perl is a mess and that's good because the
    problem space is also a mess.
    " - Larry Wall

      For my own code, sometimes it is to ensure I have a number somewhere that a number is required, eg when calling a function that treats undef differently (".. or if bool is undef, starts a game of nethack"), or badly ("use of uninitialised value"), or for storing in a NOT NULL database field. Another reason is where I need to use a different criterion for truthfulness:

      sub has_file { my $self = shift; my $filename = $self->filename; (defined($filename) && length($filename)) ? 1 : 0; }
      .. which would otherwise do the wrong thing for a filename such as "0".

      Primarily, though, it is for clarity: to make it clear in the code (and to allow me to make it clear in the docs) that this routine returns either 0 or 1 and nothing else. I think the concept of a boolean value is very useful, and have always considered it a shame that perl didn't have such a thing as a first class data type.

      The main benefit is to prevent leakage, both actual and conceptual. By 'actual', I mean returning (say) an object (that is of course TRUE in a boolean context) that means the reference count on the object is bumped, and the object may no longer be released when it could otherwise have been because someone is still holding on to the (conceptual) boolean that tells them whether they actually had the object.

      Similarly if such a quasi-boolean is used in some polymorphic context, it may do entirely the wrong thing: there are many examples of methods that allow a parameter to be any of (0 or 1 or a coderef), and various other cases where a particular type of object is allowed.

      The conceptual leakage is about clarity of thinking: if I am not sure that I have a true boolean value, I need always to consider whether it will do the right thing when I'm passing it around or using it in various ways. When I know that I definitely have either 0 or 1, my mind is freed to consider it in a much more simplistic fashion, and I can throw it around confident that it won't blow up in my face.

      Hugo

        .. which would otherwise do the wrong thing for a filename such as "0".
        Umm, perhaps I'm being too picky, but I think that was a flawed example.
        defined($filename) && length($filename)
        would evaluate correctly, regardless of the actual filename.

        Now, if you tried just $filename as the return value, that would be problematic...

        -QM
        --
        Quantum Mechanics: The dreams stuff is made of

      To further elaborate on hv's excellent response, I often want to know for a fact that a value is explicitly TRUE or explicitly FALSE. Some situations:
      • Talking with another program through an interface
      • Passing values through an API, like HTML::Template
      • Dealing with people who are cute and like to use the zero-but-true value "0E0"
      • Making it explicit to the maintainer (who is usually me, 6 months down the road) exactly what this is meant for
      • Doing validation checks so that I can be certain something is useful only in a boolean context.

      It's a minor point, but it's those details that I find separate the beginner from the expert.

      ------
      We are the carpenters and bricklayers of the Information Age.

      Then there are Damian modules.... *sigh* ... that's not about being less-lazy -- that's about being on some really good drugs -- you know, there is no spoon. - flyingmoose

      I shouldn't have to say this, but any code, unless otherwise stated, is untested

Re: Converting to boolean
by itub (Priest) on Jun 17, 2004 at 15:40 UTC
    I don't really use "explicit Booleans" in Perl because they aren't needed, but in those rare cases where I want to convert something to 0 or 1 because some other program expects it that way, I use $x = $x ? 1 : 0. It might not be the shortest, cleverest, or most illegible way available, but it's simple, clear, and gets the job done.
Re: Converting to boolean
by Anonymous Monk on Jun 17, 2004 at 03:26 UTC
    perl doesn't have booleans

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others romping around the Monastery: (3)
As of 2024-04-24 01:12 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found