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?

+1


source to share


2 answers


Behavior is consistent with what is described in perldoc perlsub

Operator

A 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

or while

, 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.

+3


source


For the purposes of the latter, expressions are foo if bar

both if (bar) { foo }

equivalent bar and foo

and similar if not equivalent or.



+1


source







All Articles