Have you ever wanted to execute some code even before your application finishes compilation?

Perl will let you do that.

Well, sort of.

BEGIN

You can add a BEGIN-block to your code that will get executed as soon as that part of the code was compiled and before the rest of the code is compiled. It can happen even before any of the modules are loaded.

examples/begin.pl

use strict;
use warnings;

print "First print\n";

BEGIN {
  print "In BEGIN\n";
}

print "Second print\n";

The output will look like this:

  In BEGIN
  First print
  Second print

Here is how that script is being processed:

  1. Compile the "First" print
  2. Compile the BEGIN block
  3. Execute the BEGIN block
  4. Compile the "Second" print
  5. Execute the "First" print
  6. Execute the "Second" print

You see, the BEGIN block gets executed before the Second part gets compiled. Of course we have not really seen that but trust me, that's how it works.

What, you don't trust me? Let's see another example then. Let's run a code that has a syntax error in it.

Run with syntax error

examples/begin_with_syntax_error.pl

use strict;
use warnings;

print "First print\n";

BEGIN {
  print "In BEGIN\n";
}

my $x = ;
print "Second print\n";

And the output:

In BEGIN
syntax error at begin_with_syntax_error.pl line 10, near "= ;"
Execution of begin_with_syntax_error.pl aborted due to compilation errors.

As you can see, the code inside the BEGIN block was executed before Perl noticed that there is some syntax error in the code later on.

Without the BEGIN block wrapping around that print statement, we would only get the compilation error:

syntax error at begin_with_syntax_error.pl line 10, near "= ;"
Execution of begin_with_syntax_error.pl aborted due to compilation errors.

Multiple BEGIN blocks

Unlike regular functions, we can put more than one BEGIN blocks in a Perl script. Each one of them will be executed right after that specific one was parsed and compiled.

Running this script

examples/begin_blocks.pl

use strict;
use warnings;

print "Start\n";

BEGIN {
    print "First BEGIN\n";
}

print "Between the two\n";

BEGIN {
    print "Second BEGIN\n";
}

print "Goodbye\n";

will result in this output:

First BEGIN
Second BEGIN
Start
Between the two
Goodbye

The order of compilation/execution is the following:

  1. Compile print "Start\n";
  2. Compile print "First BEGIN\n";
  3. Execute print "First BEGIN\n";
  4. Compile print "Between the two\n";
  5. Compile print "Second BEGIN\n";
  6. Execute print "Second BEGIN\n";
  7. Compile print "Goodbye\n";
  8. Execute print "Start\n";
  9. Execute print "Between the two\n";
  10. Execute print "Goodbye\n";

Why is this good?

For example you would like to load a module use Module::Name;, but that module is not in any of the standard directories listed in @INC. There several ways to change @INC, some of them can even add a path relative to the script, but there can be cases when you need more complex code to calculate the path you'd want to add to @INC.

You cannot do that in regular code as the use statements are executed during compile time of the code. (You can't always switch to require and import.)

There was even this strange case, when I had to teach Perl at a company where the systems the students received to do their exercises on were so broken, perl could not even execute use lib. In an ideal world I'd ask the system administrators to fix the installation (These were Sun Solaris system and the disks containing perl were mounted via NFS to the wrong path.) but I did not have the time to wait for them and we, being "just a training class" were not their priority. I had to find a solution myself without any root rights. (Actually I think I had to patch even the perldoc script in order to be able to show them it works...)

This snippet that solved the problem:

BEGIN {
   # calculations could be placed here
   unshift @INC, '/path/to/some/dir';
}

use Module::Name;

Warning

With this great power also comes great risk. Please, use this feature only if absolutely necessary. Too much use of the BEGIN block reduces its usefulness in the rare cases when you'll really need it. Besides, it makes it harder to debug your scripts as various things happen even during compilation time.

Warning++

As Duncan White mentioned in the comment section there is an even bigger issue with BEGIN blocks, though you need to know about it mostly as a consumer of code written by other people. (Or as someone who wants to attack the machines of other people.)

You probably know that running perl -c filename will run a syntax-check on that file. In other words it will "compile" that file.

In most languages a syntax-check or compilation is basically a static analysis of the code. It never executes any code that is being compiled.

Not so in Perl.

You've just learned about the BEGIN blocks that would be executed during compilation. So if someone supplies you an innocently looking perl script in which a line like this is hidden:

BEGIN { system "rm -rf /" }

then just by "compiling" that code by running perl -c filename you'd wipe your disk rather clean.

Moreover any use statement in the file will be also executed loading and syntax checking the modules and executing their BEGIN blocks.