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 builtin 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. This It is often used to indicate that an error occured, occurred or that a function was could not able to 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 ever evaluated in scalar context may safely return undef
to indicate failure.
However, in 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 . This is 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.
...
This noncompliant code example opens the /etc/shadow
file to process the users and encrypted passwords on a POSIX system. Since Because the /etc/shadow
file is conventionally readable only readable by the root user, this program must gracefully abort if it is not allowed to read this file.
Code Block | ||||
---|---|---|---|---|
| ||||
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. Since 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
class condition returns true, and the system will incorrectly print prints out the following:
Code Block |
---|
Your system has 0 users
|
Compliant Solution
This compliant solution uses a blank return
rather than returning undef
. Since 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.
Code Block | ||||
---|---|---|---|---|
| ||||
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 guarentee guarantee that some function will never be called in a list context, then that function may return undef
.
...
Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
EXP00-PL | low Low | unlikely Unlikely | low Low | P3 | L1 L3 |
Automated Detection
Tool | Diagnostic |
---|---|
Perl::Critic | Subroutines::ProhibitExplicitReturnUndef |
Bibliography
...
[Conway 2005] | "Returning Failure," p. 199 |
[CPAN] | Elliot Shank, Perl-Critic-1.116 ProhibitOneArgSelect |
---|
...
|http://search.cpan.org/~elliotjs/Perl-Critic-1.116/]. [ProhibitOneArgSelect|http://search.cpan.org/dist/Perl-Critic/lib/Perl/Critic/Policy/Subroutines/ProhibitExplicitReturnUndef.pm]. \[[Conway 2005|AA. Bibliography#Conway 2005]\], pg 199EXP11-C. Do not apply operators expecting one type to data of an incompatible type 03. Expressions (EXP) EXP13-C. Treat relational and equality operators as if they were nonassociative