2014 twenty-four merry days of Perl Feed

If if, use use if

if - 2014-12-12

There's a common newbie mistake that looks something like this:

if ($ENV{ADVENT_DEBUG}) {
  use Devel::ecember 12.25.14;
}

(I call this a newbie mistake to remind myself that I am still, now, and forever a newbie. I still make this mistake when I'm not paying attention.)

The problem, here, is that use happens at compile time, but if only controls the flow of the program at run time. This means that our debugger is loaded regardless of the environment. Whoops!

The instinct on how to fix this is often to use a BEGIN block, but it's not a very good instinct. In Perl, "compile time" and "run time" are relative. Once you've got your if in a BEGIN block, your use is in there too, and now it's still going to run earlier than your conditional!

So, what's a programmer to do?

This is where if comes in.

use if $ENV{ADVENT_DEBUG}, 'Devel::ecember';

This might look like some weird new form of Perl's postfix conditionals, but it's not weird at all. Or, at least, it's not weird syntax. It's a rarely-seen core library for solving this problem, and it works just like any other module: when you use it, its import method is called, and decides what to do next: either use the library you wanted, or not.

You may have noticed that we left something out of our code! We wanted to specify a version number for our debugger: v12.25.14. if doesn't let us do that, but Exporter comes to our rescue, at least somewhat, here:

use if $ENV{ADVENT_DEBUG}, 'Devel::ecember', '12.25.13';

It's important to realize that if isn't doing the equivalent of including a version number in a use statement. What's actually happening is that the string 12.25.13 is being passed to Devel::ecember's import routine. A little-known feature in Exporter notices when the first argument to import is version-like, and converts it to a call to the VERSION method.

What happens if the library you're conditionally loading doesn't use Exporter? Who knows! Probably nothing very good.

There's another complication, too. You can't tell if to load the library without calling its import routine. This doesn't come up often, fortunately!

On the other hand, there's another important use case for if. You can use if when you want to unimport stuff, too. The canonical, gross example of this is:

no if $] >= 5.020, warnings => "experimental::signatures";

Fortunately, that's been rendered obsolete by experimental! Instead, consider:

# It's Christmas!  Live a little!
no if (localtime)[4] == 12 - 1 && (localtime)[3] == 25, 'strict';
Gravatar Image This article contributed by: Ricardo Signes <rjbs@cpan.org>