What does Perl return from a subroutine when there is no counter statement?
I ran into this today and found it prudent to post a Q&A as I couldn't find anything like it.
Feel free to vote by closing if you find a duplicate of this question.
The following subroutine is conditionally return
output; I find this "awkward" because it is not explicit about what is returned to the caller when the condition is not met:
sub is_multiple_of_three {
my ( $value ) = @_ ;
return "$value is a multiple of 3"
unless $value % 3;
}
A quick rewrite does a short job of explaining the (more graceful) subroutine behavior under all circumstances:
sub is_multiple_of_three {
my ( $value ) = @_ ;
return if $value % 3;
return "$value is a multiple of 3";
}
When calling these both variants of the sub, I expected to find some consistency between the fact that both are return
in the context of a list:
- string when condition evaluates to true
- nothing (empty list) when the conditional value is assigned false
But, alas, the behavior was somewhat unexpected:
use strict;
use warnings;
use Data::Printer;
use feature 'say';
my %subs = (
graceful => sub {
my ( $value ) = @_ ;
return if $value % 3;
return "$value is a multiple of 3";
},
clumsy => sub {
my ( $value ) = @_ ;
return "$value is a multiple of 3"
unless $value % 3;
},
);
for my $name ( keys %subs ) {
my $sub = $subs{$name};
say $name;
my @results = map { $sub->($_) } 1 .. 10;
p @results;
}
Output
graceful
[
[0] "3 is a multiple of 3",
[1] "6 is a multiple of 3",
[2] "9 is a multiple of 3"
]
clumsy
[
[0] 1,
[1] 2,
[2] "3 is a multiple of 3",
[3] 1,
[4] 2,
[5] "6 is a multiple of 3",
[6] 1,
[7] 2,
[8] "9 is a multiple of 3",
[9] 1
]
Question
The "graceful" taste behaves as expected, but why is the "awkward" helper returning integers when the condition is false?
source to share
Behavior is consistent with what is described in perldoc perlsub
OperatorA
return
can be used to exit a subroutine, optionally specifying a return value that will evaluate to the appropriate context (list, scalar, or empty) depending on the context of the call to the subroutine. If you don't supply a return value, the routine returns an empty list in the context of a list , undefined in a scalar context, or nothing in a void context. If you return one or more aggregates (arrays and hashes), they will be flattened together into one large indistinguishable list.If no return is found, and if the last statement is an expression, its value is returned . If the last statement is a loop control structure such as
foreach
orwhile
, no return value is specified. Empty submission returns an empty list.
Graceful sub in list context :
-
True: returns a string
"$value is a multiple of 3"
-
False: returns an empty list
This is why @results
there are only three elements in it; something is added to the array only when the conditional value is true.
Clumsy sub in list context :
- True: Returns a string
"$value is a multiple of 3"
. There is no drama here. - False: if no explicit is found
return
, the value of the last expression evaluated is returned,$value % 3
So in both cases, the subroutine will return a value, so it @results
contains ten elements.
source to share