What does Perl return from a subroutine when no return statement is encountered?

Viewed 2309

I encountered this today and thought it prudent to post a Q&A as I couldn't find anything similar.
Feel free to vote-to-close if you find a duplicate of this question.


The following subroutine conditionally returns output; I consider it "clumsy" because it isn't explicit about what is returned to the caller when the conditional is not satisfied:

sub is_multiple_of_three {

    my ( $value ) = @_ ;
    return "$value is a multiple of 3"
      unless $value % 3;
}

A quick rewrite makes short work of clarifying the (more graceful) subroutine's intended behaviour 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 flavours of the subroutine, I was expecting to find some consistency between what both return in list context:

  • a string when the conditional evaluates to true
  • nothing (an empty list) when the conditional evaluates to false

But alas, the behaviour was slightly 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" flavour behaves as expected, but why is the "clumsy" sub returning back integers when the conditional is false?

2 Answers
Related