╔╗ ╔═╗╔╗╔╔═╗ ╔╗ ╔═╗╔╗╔╔═╗ ╠╩╗╠═╣║║║║ ╦ ╠╩╗╠═╣║║║║ ╦ ╚═╝╩ ╩╝╚╝╚═╝ ╚═╝╩ ╩╝╚╝╚═╝ ╔═╗╔═╗╔═╗╦═╗╔═╗╔╦╗╔═╗╦═╗ ║ ║╠═╝║╣ ╠╦╝╠═╣ ║ ║ ║╠╦╝ ╚═╝╩ ╚═╝╩╚═╩ ╩ ╩ ╚═╝╩╚═ ============================================================================ 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 ============================================================================ japh.codes