in reply to A question about method return values and error checking

Because of the context issues you mentioned, I'd use a blank return; instead of return undef;, but, other than that, I tend to agree with your coworker. If there's no defined value to return, return an undefined value.

As far as warnings and error detection/handling, you need to check the result either way to see whether it failed to get an OS name or not and checking the truthiness of the return value works just as well (and doesn't emit any warnings) regardless of whether the return value on failure is undef or an empty string.

Replies are listed 'Best First'.
Re^2: A question about method return values and error checking
by kennethk (Abbot) on Nov 04, 2015 at 17:22 UTC
    A counter example to consider: let's say the code in question was:
    printf <<EOF, $os->name( long => 1 ), $os->version; Operating System: %s Version : %s EOF
    In order for the output to make sense, you would actually want a placeholder in the list for the name. In the general case, invoking $os->name in a list context doesn't really make much sense unless you really have an explicit list of values.

    #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.

      That's resolved trivially:
      printf <<EOF, $os->name( long => 1 ) // 'unknown OS', $os->version // +'unknown version'; Operating System: %s Version : %s EOF
      If you return empty strings on failure instead of undef, then you'd need to use || instead of //, which could cause issues if 0 is a potential return value. (Not likely in the specific example of OS name/version, but relatively common in the general case.) So, personally, I'd chalk that up as another point in undef's favor.
        The discussion was about concerns that return undef; in list context returns a list that is one element long, and thus true. In contrast, a bare return; in list context returns a zero-length result. This is a point that is lost on many acolytes. return undef; might bite you if you naively did something like:
        my @names = $os->name( long => 1 ) or next; # No names
        On the other hand, of you did
        my @names = map $_->name( long => 1 ), @oses;
        you would end up with lists of different lengths with the bare return;. Your solution puts the list elements back in scalar context, and thus avoids the actual question.

        Update: I remembered where it really bites people:

        my %hash = (name => $os->name( long => 1 ), version => $os->version, );
        where the mismatch has now resulted in a transposition of keys and values.

        #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.

        The OP had an oops moment when some (poorly documented?) method was mis-used. A blank return; could make that oops even worse, in a list context. Thence the recommendation to go with return undef.

Re^2: A question about method return values and error checking
by ikegami (Patriarch) on Nov 06, 2015 at 19:07 UTC

    Because of the context issues you mentioned, I'd use a blank return; instead of return undef;

    I hate you! Functions that are expected to return a scalar should not suddenly returning nothing. It rarely has any advantage, and it fails very poorly in common situations.

    f( name => get_name(), foo => 1 );
      > f( name => get_name(), foo => 1 );

      That's because the design of => is flawed.

      It should enforce scalar context, if people want to use it as a pairing operator.

      DB<106> sub tst { return } DB<107> x a => scalar( tst() ), b=>2 => ("a", undef, "b", 2)

      And yes I know that Moose relies on this "feature", but you can't have it all.

      Cheers Rolf
      (addicted to the Perl Programming Language and ☆☆☆☆ :)
      Je suis Charlie!

        Well, the Perl 5 implementation of => has that problem. I recall discussions of enforcing scalar context when => was still fairly new, but it was already too late. Then Perl 6 made it so.

        And the problems with return; from a sub that otherwise returns a single scalar go way beyond just uses of =>, of course.

        - tye