Hi! Please consider following me on twitter: @hanekomu.

Boolean normalization using the logical negation operator

The perlsyn manpage says the following about truth and falsehood:

The number 0, the strings '0' and '', the empty list "()", and "undef" are all false in a boolean context. All other values are true. Negation of a true value by "!" or "not" returns a special false value. When evaluated as a string it is treated as '', but as a number, it is treated as 0.

Sometimes you want to normalize a value so that it is 1 if it is a true value and 0 if it is a false value. This is sometimes called boolean normalization.

Usually you will see something like this:

my $b = $value ? 1 : 0;

There is an easier way. You could make use of the logical negation operator, !. When it is applied to a true value, it returns a dual value that is the number zero in numerical context and the empty string in string context. When the logical negation operator is applied to a false value, it returns a dual value that is the number 1 in numerical context and the string "1" in string context. Let's see this in detail:

$ perl -MDevel::Peek -le'Dump !42'
SV = PVNV(0x802000) at 0x12fef8
  REFCNT = 2147483647
  FLAGS = (IOK,NOK,POK,READONLY,pIOK,pNOK,pPOK)
  IV = 0
  NV = 0
  PV = 0x200160 ""\0
  CUR = 0
  LEN = 4

$ perl -MDevel::Peek -le'Dump !0'
SV = PVNV(0x802014) at 0x12ff08
  REFCNT = 2147483646
  FLAGS = (IOK,NOK,POK,READONLY,pIOK,pNOK,pPOK)
  IV = 1
  NV = 1
  PV = 0x200170 "1"\0
  CUR = 1
  LEN = 4

By using the logical negation operator twice you can therefore simplify the above statement to:

my $b = !!$value;

And if you wanted the opposite boolean normalization, it's even easier:

my $b = $value ? 0 : 1;

becomes:

my $b = !$value;

Write a comment | Bookmark and Share

posted at: 08:22 | path: /dev | permalink | 11 comments | 0 trackbacks

Use parent.pm instead of base.pm

For years, the common way for your class to inherit from one or more superclasses was the base module. For example:

package Game;
sub new { bless {}, shift }

package Baduk;
use base 'Game';

This works, but some people, me included, aren't quite happy with that. Basically, the above could also be expressed as:

package Game;
sub new { bless {}, shift }

package Baduk;
our @ISA = qw(Game);

If the two packages were in different files, the Baduk package would have to load the file where the Game package lives in as well. But that's about it.

However, base.pm goes further than that. It supports deprecated pseudohases, tries to be clever with $VERSION and generally just does too much. A lot of cruft has accumulated over the years. So a new module, parent, was forked from base.pm and cleaned up.

Using parent.pm is pretty much the same as base.pm:

package Game;
sub new { bless {}, shift }

package Baduk;
use parent 'Game';

This will try to load Game.pm as well. If the Game package is in a different file that is already loaded, you can tell parent.pm not to try to load the file:

package Game;
sub new { bless {}, shift }

package Baduk;
use parent -norequire, 'Game';

Compare the source of the two modules and you will find that parent.pm is a lot cleaner and easier to understand.

Write a comment | Bookmark and Share

posted at: 23:26 | path: /cpan_gems | permalink | 3 comments | 0 trackbacks