There are two major ways indicating failure in a function. One of them is to throw (or raise) an exception by calling die, croak, or some other method. The other one is to return a false value. In Perl this false values is usually an undef. Some people claim that throwing an exception is a better way to indicate error, but in case you (or the people who wrote the code-base) have decided to return undef then the question remains: How to return undef? Actually returning undef from a function is simple, but due to the context sensitivity of perl it has several gotchas. We just have to decide which one to avoid and which one to fall in.

Return undef explicitly (and what's wrong with that)

The solution that seems to be obvious to many people, especially who are new to Perl, is to explicitly return undef by writing: return undef;. This is what we try in the following example. We have a function called div that will attempt to divide two numbers, but if the denominator is 0, we must signal an error as we cannot divide by 0. In that case we call return undef; We call the div function 4 times. Twice we assign the value to a scalar variable and twice we assign it to an array.

Then we check if the result is true. For a scalar we use (if (defined $x)), but for arrays, we usually check truth by checking if the array is empty (if (@x_results)).

examples/explicit_return_undef.pl



use 5.010; use strict; use warnings; sub div { my ($x, $y) = @_; if ($y !=0 ) { return $x/$y; } return undef; } my $x = div(6, 2); if (defined $x) { say "Success! The results is $x"; } else { say "Failure! We received undef"; } my $y = div(42, 0); if (defined $y) { say "Success! The results is $y"; } else { say "Failure! We received undef"; } my @x_results = div(6, 2); if (@x_results) { say "Success! We can divide 6 by 2"; } else { say "Failure!"; } my @y_results = div(42, 0); if (@y_results) { say "Success! We can divide 42 by 0"; } else { say "Failure!"; }

The result looks like this:

Success! The results is 3 Failure! We received undef Success! We can divide 6 by 2 Success! We can divide 42 by 0

The first 3 results are correct, but then in the 4th row we see an incorrect result. This code now thinks that perl can divide by 0.

The problem is that our function returned undef which got assigned to the @y_results array which means the content of the array became a single undef. As if we wrote @y_results = (undef);. A one-element array is not empty, even if that element is undef, and thus if (@y_results) returned true.

So let's try another solution.

Return undef implicitly

The only thing we changed is that now, in case of error, we call return; without explicitly returning undef

examples/implicit_return_undef.pl



use 5.010; use strict; use warnings; sub div { my ($x, $y) = @_; if ($y !=0 ) { return $x/$y; } return; } my $x = div(6, 2); if (defined $x) { say "Success! The results is $x"; } else { say "Failure! We received undef"; } my $y = div(42, 0); if (defined $y) { say "Success! The results is $y"; } else { say "Failure! We received undef"; } my @x_results = div(6, 2); if (@x_results) { say "Success! We can divide 6 by 2"; } else { say "Failure!"; } my @y_results = div(42, 0); if (@y_results) { say "Success! We can divide 42 by 0"; } else { say "Failure!"; }

This time the result is correct:

Success! The results is 3 Failure! We received undef Success! We can divide 6 by 2 Failure!

This happens because the parameter-less return has the magic feature that in scalar context it returns undef, but in list context it returns an empty list ().

Sounds perfect.

It is not.

Prohibit Explicit Return Undef

Before showing the problem with this solution though, let's see how can we avoid the first problem. How can we make sure that we don't have explicit return undef; in our code?

Because this issue was part of the original Perl Best Practices book of Damian Conway, Perl::Critic has a policy against it called Subroutines::ProhibitExplicitReturnUndef.

If, following the advice to check one policy at a time we run the next command:

perlcritic --single-policy Subroutines::ProhibitExplicitReturnUndef examples/explicit_return_undef.pl

we will get a report:

"return" statement with explicit "undef" at line 11, column 5. See page 199 of PBP. (Severity: 5)

Using this policy in our setup (e.g. in the .perlcriticrc file), will help us locate the places where undef was returned explicitely, and it will make sure we get notified if some adds such code to our code-based.

When implicit return breaks our code

I promised to show when the second solution, the implicit return of undef, by calling a simple return; will break our code.

First let's see a code snippet using explicit return undef using return undef;:

examples/explicit_return_undef_hash.pl



use 5.010; use strict; use warnings; use Data::Dumper qw(Dumper); sub div { my ($x, $y) = @_; if ($y !=0 ) { return $x/$y; } return undef; } my %results = ( '42/0' => div(42, 0), '6/2' => div(6, 2), ); print Dumper \%results;

The result is

$VAR1 = { '42/0' => undef, '6/2' => '3' };

what we expected.

Now lets see the same code but with implicit return undef using return;

examples/implicit_return_undef_hash.pl



use 5.010; use strict; use warnings; use Data::Dumper qw(Dumper); sub div { my ($x, $y) = @_; if ($y !=0 ) { return $x/$y; } return; } my %results = ( '42/0' => div(42, 0), '6/2' => div(6, 2), ); print Dumper \%results;

The result is really strange:

$VAR1 = { '42/0' => '6/2', '3' => undef };

How did '3' become a key and '6/2' a value in this hash?

The only clue we might get is the Odd number of elements in hash assignment ... warning.

The problem here is that we basically have

'42/0' => , '6/2' => 3,

which is the same as

'42/0', , '6/2', 3,

In the first row we don't have a value and perl disregards that place where we have two comma one after the other. Which means perl actually sees this:

'42/0' => '6/2', 3 => ,

So we have 3 elements in the hash assignment (an odd number) and perl fills in the missing last value with undef.

This happens because in this case the div calls were in list context and the function returned an empty list.

So the same thing that helped us earlier, that the empty return; gives an empty list in list context, now breaks our code.

So after all this solution isn't perfect either.

Alway enforce scalar context

The user of our function can solve this by putting the call to div into scalar context:

examples/implicit_return_undef_hash_with_scalar.pl



use 5.010; use strict; use warnings; use Data::Dumper qw(Dumper); sub div { my ($x, $y) = @_; if ($y !=0 ) { return $x/$y; } return; } my %results = ( '42/0' => scalar div(42, 0), '6/2' => scalar div(6, 2), ); print Dumper \%results;

The result is correct then:

$VAR1 = { '42/0' => undef, '6/2' => '3' };

but this means the user has to remember to put scalar in front of the call.

It is still probably better than the explicit return undef, but it is not exactly DWIM.

Forbid list context

Seeing all this trouble, and seeing that the trouble only manifests when the function is called in list context, as the author of the div function, we can decide to forbid calling the function in list context.

We can use wantarray to recognize when is the function called in list context and throw an exception (using croak):

examples/prohibit_list_context.pl



use 5.010; use strict; use warnings; use Data::Dumper qw(Dumper); use Carp qw(croak); sub div { my ($x, $y) = @_; croak 'Cannot use "div" in list context' if wantarray; if ($y !=0 ) { return $x/$y; } return; } my $x = div(6, 2); print "$x

"; my %results = ( '42/0' => scalar div(42, 0), '6/2' => scalar div(6, 2), ); print Dumper \%results; my @y = div(6, 2);

The result is that we will soon find all the places where we have called the function in list context and will be forced to fix those places.

3 $VAR1 = { '42/0' => undef, '6/2' => '3' }; Cannot use "div" in list context at examples/prohibit_list_context.pl line 9. main::div(6, 2) called at examples/prohibit_list_context.pl line 20

Of course this means we cannot use the function in list context, for example we cannot write:

print "The result of 6/2 is ", div(6, 2);

but we can write

print "The result of 6/2 is ", scalar div(6, 2);

or even

print "The result of 6/2 is " . div(6, 2);