perl.gg / secret-operators

Bang Bang Operator

2026-01-01

Two negations. That's the trick:
!!
The bang bang operator. It converts any value to a clean boolean.
!!0 # '' (empty string, false) !!1 # 1 (true) !!'hello' # 1 (true) !!'' # '' (false) !!undef # '' (false)
Not just truthy or falsy - actual Perl boolean values.

Part 1: THE TRICK

Single negation flips true to false and vice versa:
!0 # 1 (false became true) !1 # '' (true became false)
Double negation flips twice - back to the original truthiness:
!!0 # '' (false -> true -> false) !!1 # 1 (true -> false -> true)
But now you have a normalized boolean, not the original value.

Part 2: WHY BOTHER

Consider this:
my $value = 'hello world'; my $truthy = $value; # 'hello world' (keeps original) my $bool = !!$value; # 1 (clean boolean)
Without bang bang:
print $truthy; # hello world print $bool; # 1
The second form is explicitly boolean. Useful when you need to pass a true/false flag, not the actual value.
.--. |o_o | |:_/ | // \ \ (| | ) /'\_ _/`\ \___)=(___/

Part 3: PERL'S BOOLEAN VALUES

Perl doesn't have true/false keywords. It uses:
False: 0, '', '0', undef, empty list True: Everything else
The bang bang operator normalizes to exactly two values:
'' for false 1 for true
These are Perl's canonical boolean representations.

Part 4: FLAG NORMALIZATION

Storing user input as a boolean:
my $input = param('subscribe'); # Could be 'yes', '1', 'on', 'true'... my $flag = !!$input; # Now it's 1 or '' # Later: if ($flag) { send_newsletter(); }
You don't care what they typed. You care if it was truthy.

Part 5: COMPARISON RESULTS

Comparisons return 1 or '' in Perl:
my $is_big = 10 > 5; # 1 my $is_small = 5 > 10; # ''
So bang bang on a comparison is redundant:
my $is_big = !!(10 > 5); # 1 (same as without !!)
But it documents intent - "this is meant to be a boolean."

Part 6: WITH REGEX

Regex matches return true/false in scalar context:
my $matched = $str =~ m~pattern~; # 1 or ''
Bang bang doesn't change it:
my $matched = !!($str =~ m~pattern~); # Still 1 or ''
But it can help with non-boolean regex returns:
my @matches = $str =~ m~(\w+)~g; # List of captures my $has_match = !!@matches; # 1 or '' (was it empty?)

Part 7: CONVERTING TO INTEGER

Sometimes you need 0/1 integers, not ''/ 1:
my $bool = !!$value; # '' or 1 my $int = 0 + !!$value; # 0 or 1 (Venus + Bang Bang)
This is the "Venus Bang Bang" combination:
0 + !!$anything # Always gives you 0 or 1 integer
Useful for:
- Bit manipulation - JSON output - Database storage - C library interfaces

Part 8: COUNTING TRUES

Count how many values are truthy:
my @values = (1, 0, 'hello', '', undef, 42); my $count = 0; $count += !!$_ for @values; print "True values: $count\n"; # True values: 3
Or more tersely with grep:
my $count = grep { $_ } @values; # 3
But bang bang makes the intent crystal clear.

Part 9: CONDITIONAL DEFAULTS

Set a flag based on existence:
my %opts = (verbose => 1, debug => 0); my $v = !!$opts{verbose}; # 1 my $d = !!$opts{debug}; # '' (0 is false) my $q = !!$opts{quiet}; # '' (doesn't exist)
Without bang bang, you'd have to check defined and truthiness separately.

Part 10: JSON BOOLEANS

Many JSON modules need explicit booleans:
use JSON; my $data = { active => !!$user->{status}, admin => !!$user->{is_admin}, }; print encode_json($data); # {"active":true,"admin":false}
The JSON module recognizes Perl's canonical booleans and converts them properly.

Part 11: DEBUGGING

When you're unsure what's truthy:
for my $val (0, 1, '', 'hello', undef, [], {}) { printf "%s -> %s\n", defined $val ? "'$val'" : 'undef', !!$val ? 'true' : 'false'; }
Output:
'0' -> false '1' -> true '' -> false 'hello' -> true undef -> false 'ARRAY(0x...)' -> true 'HASH(0x...)' -> true
References are always true (they're not empty or zero).

Part 12: THE NAME

Two bangs:
!!
Bang. Bang.

Some call it "double not" or "not not." But bang bang is funnier, and it sounds like you're shooting truth out of any value.

JavaScript has the same operator with the same name. Perl did it first, of course.

!! / \ ! ! / \ false -> true -> normalized Shooting booleans since forever
perl.gg