Skip to end of metadata
Go to start of metadata

Perl expressions can be interpreted in either scalar or list context, depending on the syntactic placement of the expression. Many functions are designed to return only a scalar or only a list. Many built-in functions can be called in both contexts, and they may return differing values for each. Furthermore, any function may specify exactly what to return in each context.

Returning the value undef is a common convention for a function to indicate it has no return value. It is often used to indicate that an error occurred or that a function could not successfully complete an operation. When used as the conditional in a conditional expression (such as in an if statement), undef evaluates to false. Therefore, a function that is evaluated only in scalar context may safely return undef to indicate failure.

In list context, things are slightly more complicated. An empty list, when evaluated in a boolean condition, evaluates to false. But the value undef, when evaluated in list context, evaluates to true because it is converted to a list with the singleton value undef. Therefore, a function should not return undef if it might ever be invoked in list context.

Noncompliant Code Example

This noncompliant code example opens the /etc/shadow file to process the users and encrypted passwords on a POSIX system. Because the /etc/shadow file is conventionally readable only by the root user, this program must gracefully abort if it is not allowed to read this file.

sub read_users {
  open( my $filehandle, "<", "/etc/shadow")
    or return undef;
  my @users = <$filehandle>;
  return @users;
}

# ...

if (my @users = read_users($filename)) {
  print "Your system has $#users users\n";
  # process users
} else {
  croak "Cannot read shadow file";
}

The read_users() subroutine returns undef if it cannot open /etc/shadow, but it returns a list of user data entries if it succeeds. Because its output is used in list context, a return value of undef is converted to a list of a single element: (undef). Consequently, the if condition returns true, and the system incorrectly prints out the following:

Your system has 0 users

Compliant Solution

This compliant solution uses a blank return rather than returning undef. Because a blank return is always interpreted as false in list or scalar context, the program will properly complain if it cannot read the shadow file.

sub read_users {
  open( my $filehandle, "<", "/etc/shadow")
    or return;
  my @users = <$filehandle>;
  return @users;
}

Exceptions

EXP00-PL-EX1: This recommendation applies specifically to functions called in a list context. If you can guarantee that some function will never be called in a list context, then that function may return undef.

Risk Assessment

Improper interpretation of return undef can lead to incorrect program flow.

Recommendation

Severity

Likelihood

Remediation Cost

Priority

Level

EXP00-PL

Low

Unlikely

Low

P3

L3

Automated Detection

Tool

Diagnostic

Perl::Critic

Subroutines::ProhibitExplicitReturnUndef

Bibliography

 


3 Comments

  1. The perlop() manpage seems to prefer 'boolean', although I've also seen 'Boolean' used interchangeably. We should choose one and stick to it....I'd suggest using 'boolean', unless 'Boolean' is preferred in contexts outside of Perl.

  2. Thanks for correcting "if class condition." That's why I appreciate your comments-next time I see it, I'll know it's wrong-and if I see "else class condition," I'll figure that's wrong too. (Did I get the concept, or is it more complicated than that?)

    I went by the SEI Style Guide (and Addison-Wesley's style) on boolean/Boolean. I agree Boolean has seen enough use that, like french fries, it's okay lowercase. But the "official" sources, like Oxford Dictionary of Computing, still cap it.

    1. I think the concept is that the components of an if statement are the conditional, the then-clause, and the else-clause. And this pretty much occurs in every programming language.

      My offhand impression is that we should use the terminology & style employed by the Perl community. Sometimes the community has distinct nuances, like 'filehandle'. I suspect that originates from Larry Wall, the creator of Perl. Other times they don't agree, such as boolean/Boolean. I do see 'boolean' more often in the Perl docs than 'Boolean', but there's enough of both that we could use whichever one we want. There is no 'boolean' keyword in Perl, and Larry's documentation uses both 'boolean' and 'Boolean'.