try/catch in Perl – eval

Perl eval built-in function is very powerful and it implements the function of try/catch as Java. In this article I will review how to use eval.

Let’s see some example that will terminate the perl program:

1. $division = $dividend/$divider # so what happen if $divider = 0?

2. open FILE, “filenotexist.txt”; # file not exist, then it will halt

eval will help try catch your exceptions in perl runtime (why I bold ‘runtime’ here I will explain below). eval is not like a where or if, so you have to have a ‘;’ after its statement, e.g,

eval {$division = $dividend/$divider};#try

It will help catch the exception here, like ‘Illegal division by zero at eval.pl line 11.’. It just likes the ‘try’ in Java.

After that, you can use below ‘catch’ statement to handle the exception.

print “Error captured: $@\n” if $@;#catch

Here if no exception happens (e.g, 2/1), then $@ will be undef and the print statement will not be executed. Otherwise, the error will be stored in $@ and get printed.

Pls. note that perl eval can not catch following errors:

1. Error crashes the perl interpter. E.g, Running out of memory, Uncaught signal

2. Can not catch any ‘warnings’

Besides that, perl could also not be able to catch an ‘exit’.

Below is the sample script:

#! /usr/local/bin/perl
#luohua.huang@gmail.com
##################################
# eval function
##################################

eval { 1/1 ; }; #try
print “Error captured 1: $@\n” if $@; #catch. Here no exception then no action.

my $zero = 0;
eval { my $a = 1/$zero ; print “$a \n”;};#try
print “Error captured 2: $@\n” if $@;#catch. Here it will catch the Illegal division by zero error. the print “$a” has no chance to run.

eval { die; };#try
print “Error captured 3: $@\n” if $@;#catch. Here it will catch the ‘die’ error.

eval {
open FILE, “filenotexist” or die “Can not open file filenotexist: $!”;
};#try
print “Error captured 4: $@\n” if $@;#catch. Here it will catch the Cannot open a file error.

eval {
exit;
};#try
print “Error captured 5: $@\n” if $@;#catch. Here it has no chance to catch the error as it exits!

Output:

(luhuang) public_html- ./eval.pl

(luhuang) public_html- ./eval.pl
Error captured 2: Illegal division by zero at ./eval.pl line 11.

Error captured 3: Died at ./eval.pl line 14.

Error captured 4: Can not open file filenotexist: No such file or directory at ./eval.pl line 18.

 

Let me answer why I bolded runtime, take below command as example,

(luhuang) public_html- perl -lwe ‘eval{0/0}’
Illegal division by zero at -e line 1.
(luhuang) public_html-

The exception even happens before the eval block is entered! That is because perl calcuates immediate expressions during compile time.

So if in above sample script, if I used the immediate expressions as input,

eval { my $a = 1/0 ; print “$a \n”;};#try
print “Error captured 2: $@\n” if $@;#catch. Here it will not run the eval even! It is because 1/0 is immediate expression and will be executed in compile time but eval could #catch only runtime exceptions.