Perl Pragma Primer (1/2) | WebReference

Perl Pragma Primer (1/2)

current pageTo page 2
[next]

Perl Pragma Primer

By Dan Ragle

Digg This Add to del.icio.us

A bug in my Simple Comments script got me thinking this week about the use of pragmas in Perl; specific instructions that we can embed in Perl code, depending on our needs and preferences, that allow our scripts to be compiled and behave differently than they would otherwise. Though we use pragmas in most of our Perl scripts (one in particular is recommended for almost all scripts, especially those of beginners), we rarely think about them. How exactly do pragmas work? When we add the simple:

use strict;

to the top of our scripts, what magic is being performed behind the scenes that causes the Perl interpreter to subsequently reject the bulk of our remaining code as not worthy of being compiled?

Conditional Perl Pragmas

In my own example, the bug that got me thinking about pragmas in general is represented by the following simple code snippet:

if ($] 

(Actually, in the live script I got the variable wrong, too; but as we'll see in a moment that doesn't matter.1) The idea was a simple one. Having been warned in perldoc that I shouldn't use utf8 in a Perl 5.8 script unless I was actually embedding utf8 within the script itself, I decided I would conditionally apply the utf8 pragma only if the script was running on an older interpreter. The $] variable holds the numeric version of the running interpreter, so I used the pragma if the Perl version was less than 5.8 (5.008 in the actual variable). While simple, it was ineffective; and while it executed, it doesn't actually apply the utf8 pragma to the remainder of my code! One right way to do it looks like this:

BEGIN {
   if ($] import();
   }
}

To fully understand why that one works (and why my earlier attempt failed) we need to back up a step and learn about what goes on behind the scenes when Perl pragmas are invoked.

use-ing Pragmas

The most common way to invoke a pragma in a Perl script is via the use statement, which I described in a previous tutorial that focused on the use of modules. Pragmas are separate Perl modules that follow the same rules and constructs of their more common counterparts; specifically, they have their own package namespaces, implement (if necessary) their own package variables, and define their own import routines, resulting in your script being somehow altered or enhanced by the pragma's executed code. Some of the more common pragmas we may see include the venerable use strict;, which is recommended for use in most scripts (forcing stricter variable declarations and usages); as well as use warnings; (outputs messages for common--but syntactically valid--scripting errors) and use diagnostics; (provides extended developer information for error and warning messages).

The most important similarity between a regularly used module and a pragma is that pragmas are also loaded at compile-time, i.e., they're loaded and executed as the Perl script is being compiled (this is a feature of the use statement itself; pragmas just leverage the same mechanism). Additionally, like any other module, their import routines are also executed during the compilation phase of the script. This is important, because in order to be effective, most pragmas--as we'll see in a moment--must apply their pragmatic effects to the code as it's being compiled, and not at runtime. For example, if you put use strict; in your code, the compiler knows it needs to perform a stricter analysis of the script's variable declarations (among other things) as the rest of the code is being compiled (how it knows this we'll learn a little later in this tutorial). In other words, the execution of a pragma often changes the way the rest of the code block following the pragma is compiled. Thus the use statement is an ideal vehicle with which to launch a needed pragma, since it's executed during the compile-phase of the script.

Some Pragmas are Scoped Lexically

I mentioned in the previous paragraph that a pragma, when used, changes the way the rest of the code block following the pragma is compiled; and herein lies an imporant difference between the use of pragmas and regular code modules in Perl scripts. Some pragmas are scoped lexically, meaning that they affect only the remainder of the innermost enclosing block that they were called within.2 For example, in the following code, strict-ness is only applied to the statements that are executed when the variable $foo is true:

if ($foo) {
   use strict;
   my $bar = 'foobar';
   print $bar;
}
else {
   $baz = 'foobaz';
   print $baz;
}

Note that it doesn't really matter what $foo actually is. As the statements are being interpreted (and since the use strict is actually executed) at compile-time, the compiler simply enforces its strict checking within the first conditional block, but not the second. If we had written:

if ($foo) {
   use strict;
   $bar = 'foobar';
   print $bar;
}
else {
   $baz = 'foobaz';
   print $baz;
}

We would have been told of the error declaring $bar in the first block (i.e., Global symbol "$bar" requires explicit package name) and the interpreter would have refused to execute our script. Note how this differs from typical modules: With a module, the import routine can (and often does) pull in code that can be used in any area of your script. i.e. It imports the module's symbols into the current package, making them available throughout your current script (specifically, your current package) and not just the current code block. For example:

#!/usr/bin/perl -T
use strict;
use warnings;
my $foo = 0;
if ($foo) {
   use Time::Local;
}
else {
   # timelocal is imported from the 
   # Time::Local module above
   my $lt = timelocal(0, 0, 0, 1, 0, 2008);
   # print the epoch for 1/1/2008
   print $lt, "\n";
}

Taking the above two points together (pragmas are invoked at compile-time and often scoped lexically) it's easy to now see why my initial example failed:

if ($] 

While my intentions were good, the utf8 pragma--when executed as above--would only affect the statements within the innermost enclosing block; or in other words, the pragma wouldn't have any effect at all! It would actually be executed (the compiler would see the use statement and execute it), but its effect would not have lasted outside of the very block it's called within. If you're having any trouble seeing the problem, here's an expanded version that will hopefully explain what's happening:

if ($] 

This explains why my logic was faulty. But how do we fix it? Again, the answer requires that we first understand a little bit more about what happens in the pragma modules themselves.


1. For those of you running Simple Comments, no need to worry. The problem I thought I was fixing with the errant code was actually fixed via other logic I had already added to the script; and the example above--as I explain in this tutorial--isn't doing anything harmful. I'll correct it in a future version of the script.

2. A few of the key exceptions to this rule are use subs, use vars, and use lib.


current pageTo page 2
[next]

Created: May 2, 2008
Revised: May 2, 2008

URL: http://webreference.com/programming/perl/pragmas/index.html