Converting to boolean
dragonchild
created: 2004-06-16 23:16:32
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

Re: Converting to boolean
created: 2004-06-16 23:26:31
perl doesn't have booleans
Re: Converting to boolean
created: 2004-06-16 23:41:07

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
created: 2004-06-16 23:49:18

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 node 133554.

After Compline,
Zaxo

Re: Converting to boolean
created: 2004-06-16 23:50:02

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
created: 2004-06-17 00:32:21

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
hv
created: 2004-06-17 10:19:41

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
created: 2004-06-17 10:40:52
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.
Re^2: Converting to boolean
created: 2004-06-18 14:38:44
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?)
Re^3: Converting to boolean
created: 2004-06-18 15:09:21
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
created: 2004-06-17 11:40:42
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
created: 2004-06-17 11:53:16
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

Re^2: Converting to boolean
hv
created: 2004-06-17 12:38:34

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

Re^3: Converting to boolean
QM
created: 2004-06-17 21:42:45
.. 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

Re^2: Converting to boolean
created: 2004-06-17 13:46:48
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

perlmonks.org content © perlmonks.org and Anonymous Monk, davido, diotalevi, dragonchild, dvergin, hv, itub, QM, Roy Johnson, Sidhekin, tilly, Zaxo

prlmnks.org © 2006 edmund von der burg (eccles & toad)

v 0.03