I typically code my subroutines that need to indicate 'nothing to be returned' as
sub do_nothing { ... # return 'nothing' return (); }

This style grew out of a discussion I had with rob_au about when you need to use the

wantarray ? : ;
operator (typically very rarely).

However, I started to question whether this was really expressing what I wanted to do in most cases.

I wrote this code to test different ways of returning 'nothing' or failure, in list and scalar contexts.

#!/usr/bin/perl -w use strict; use Benchmark; use Data::Dumper; my $scalar; my @list; my %funcs = ( nothing => \&nothing, _undef => \&_undef, empty => \&empty, zero => \&zero, ); foreach my $func (keys %funcs) { no strict 'refs'; my $scalar = &{$funcs{$func}}(); print STDERR "scalar context $func == ", Dumper($scalar), "\n"; my @list = &{$funcs{$func}}(); print STDERR "list context $func == ", Dumper(\@list), "\n"; } sub nothing { return ; } sub _undef { return undef; } sub empty { return (); } sub zero { return 0; }
and the output from this is
scalar context _undef == $VAR1 = undef; list context _undef == $VAR1 = [ undef ]; scalar context zero == $VAR1 = 0; list context zero == $VAR1 = [ 0 ]; scalar context empty == $VAR1 = undef; list context empty == $VAR1 = []; scalar context nothing == $VAR1 = undef; list context nothing == $VAR1 = [];
So what do we learn from these ?

Well, you _probably_ rarely want to do this

sub routine { return undef; }
given the fact that in list context this results in a list with one element, whose value is undefined.

Also, when operating in list context, you probably want to rarely do this

sub routine { return 0; }
as this also results in a one element list, whose value is zero, rather than 'nothing'.

So the functions empty() and nothing() seem correct in most contexts, so which should you use ?

I then benchmarked the code thus

#!/usr/bin/perl -w use strict; use Benchmark; use Data::Dumper; my $scalar; my @list; my %funcs = ( nothing => \&nothing, _undef => \&_undef, empty => \&empty, zero => \&zero, ); timethese(10000000, \%funcs); sub nothing { return ; } sub _undef { return undef; } sub empty { return (); } sub zero { return 0; }
with these results
Benchmark: timing 10000000 iterations of _undef, empty, nothing, zero. +.. _undef: 2 wallclock secs ( 0.89 usr + -0.01 sys = 0.88 CPU) @ 11 +363636.36/s (n=10000000) empty: 2 wallclock secs ( 1.09 usr + 0.00 sys = 1.09 CPU) @ 91 +74311.93/s (n=10000000) nothing: 0 wallclock secs ( 0.50 usr + 0.00 sys = 0.50 CPU) @ 20 +000000.00/s (n=10000000) zero: 0 wallclock secs ( 0.06 usr + 0.00 sys = 0.06 CPU) @ 16 +6666666.67/s (n=10000000)

(Love that negative sys time - is Chronos gonna come for me to get it back ??)

So if we take the fact that _most_ of the time only empty() or nothing() will perform correctly, we can see that return; is more than twice as fast as return ();. This can probably be attributed to the construction, copy and destruction of the list in empty().

So if return; is just as right as return(); , but twice as fast, when would you use return(); ?

I feel that if your subroutine is constructing and returning a list, then return(); would result in more readable code e.g.

sub build_list { my ($arg1, arg2, ...) = @_; my @list = (); ... if (something) { return @list; } else { return (); } }
This to me _reads_ clearly that an empty list is being returned by a function that operates on lists.

Correspondingly, return; would be better in functions that deal with scalars, as we dont have to worry about the context.

+++++++++++++++++
#!/usr/bin/perl
use warnings;use strict;use brain;

Edited by Chady -- added readmore tag.

Replies are listed 'Best First'.
Re: Functions that return nothing, nada, failure...
by tkil (Monk) on Jun 01, 2004 at 07:30 UTC
    So if return; is just as right as return ();, but twice as fast, when would you use return();?

    I vaguely remember the meme "use return with no arguments to return false to any context" as received wisdom, but I can't find any such citation.

    I would argue that it is sufficiently common usage that it should probably be the default way to signal "false" unless you have good reason otherwise.

    If you find yourself in the situation where there are no valid sentinel values to indicate "false" (perhaps you are returning a list where the empty list might be a perfectly valid response) then you need to signal failure some other way. Three come immediately to mind:

    1. Exceptions. This is my preferred technique.
    2. Extra return values. Ugly, but since perl allows for multiple return values, this is workable. (A related technique is passing in a reference to a status variable.)
    3. Global variables. Also ugly. Think errno in C (and how its use forced the rewriting of many calls to make them reentrant, by using the "pass status variable by reference" technique.)

    In my own code, I can mostly get away with dealing with empty lists as a normal occurance; if I don't get any answers back, then I just don't do anything. Relying on foreach, map, etc, and avoiding keeping any meta-data about these collections in other variables makes this style straightforward and easy to read.

    Exceptions let me write most of my code without worrying about the corner cases; I catch those exceptions towards the top of my code, where I have large chunks of work that I can either accept or reject ("commit" or "rollback", if you like.)

    (One thing I would love is if the Fatals module would create detailed exception objects for every call mentioned; currently it is a bit cumbersome to customize the details for each case, so I still have ... or die "..." chunks throughout my code.)

      I vaguely remember the meme "use return with no arguments to return false to any context" as received wisdom, but I can't find any such citation.

      From perldoc -f return:

      If no EXPR is given, returns an empty list in list context, the undefined value in scalar context, and (of course) nothing at all in a void context.

      :-)

        [snarky quote from perlfunc omitted]

        Ha ha. :)

        Unfortunately, it's not clear that this is an endorsement of using the naked return to signal false or failure: it is only a statement that it will, in fact, return something which will be interpreted as false by perl in whatever context it is called from. The question at hand, though, is whether there is any argument (either from authority or from a rational basis) for declaring the naked return as the "best" way to return false.

        At the least, I would argue that using it fits the principle of least surprise. (I wouldn't want to have a list that explicitly returns undef suddenly be interpreted as "true" just because I changed the context I was returning it into.)

        I actively dislike the solutions recommended so far (always return either undef or (), and then document it). Unless there is a very specific reason to do otherwise, I would prefer that people just use the naked return and let the calling context figure out what to do with it.

Re: Functions that return nothing, nada, failure...
by graff (Chancellor) on Jun 01, 2004 at 05:01 UTC
    sub build_list { my ($arg1, arg2, ...) = @_; my @list = (); ... if (something) { return @list; } else { return (); } }
    This to me _reads_ clearly that an empty list is being returned by a function that operates on lists.

    Well, if that sub is actually set up so that @list only gets things pushed into it when "something" is true, then you don't need the two different return conditions -- that is:

    sub build_list { ... my @list = (); if ( something ) { push @list, $whatever, ...; } return @list; # list could still be empty at this point }
    and when @list is empty, that return statement is exactly equivalent to "return ();" -- to me, this reads even more clearly.
Re: Functions that return nothing, nada, failure...
by hossman (Prior) on Jun 01, 2004 at 06:24 UTC

    My opinion on this subject hasn't really changed in past 1.5 years.

    Returning an empty list may seem like the "safe" thing to do on error (because undef in list context is a single element list which might be construed as "success") but it's jsut as prone to confusion as returning an empty list, which might get flattened into another list and cause other problems latter on. At least with an undef, people with warnings on will get a "Use of uninitialized value..." as soon as they try to use the results from your function.

    But in the end, it really doesn't matter which approach you take, as long as you document the behavior extensively, and make it the callers responsibility to force the calling context as needed to get a result that makes sense to them.

Re: Functions that return nothing, nada, failure...
by adrianh (Chancellor) on Jun 01, 2004 at 09:51 UTC
    So if return; is just as right as return(); , but twice as fast, when would you use return(); ?

    In general I wouldn't ;-)

    I guess the only two reasons I can think of to prefer return () would be:

    • For those people unfamiliar with Perl. In other languages a bare return has often has different semantics (e.g. value of last expression). Making it explicit may help people unfamiliar with Perl. However it would be much better to educate these users rather than code for them IMHO.
    • If you were coding a routine that was only being called in list context then it might make sense to use return () just to make it a little more obvious that you were thinking in terms of lists rather than scalars in the code.
Re: Functions that return nothing, nada, failure... (depends)
by tye (Sage) on Jun 01, 2004 at 15:17 UTC

    Try adding this bit of code:

    my %results= ( nothing => nothing(), _undef => _undef(), empty => empty(), zero => zero(), );

    And you'll end up with:

    { "nothing" => "_undef", "" => "empty", "zero" => 0, }

    Which shows why you should return undef; for failure in functions that never return more than one item.

    but twice as fast

    *sigh* removing the obfuscation from your results (have you heard of 'cmpthese' -- much better if you want to post your premature nano-optimization results)

    _undef: 11,363,636.36/s empty: 9,174,311.93/s nothing: 20,000,000.00/s zero: 166,666,666.67/s

    How can you pass up the 10-times faster version that does return 0?? I mean, all you have to do is have a script that returns 100million times, and it will suddenly run... a couple of seconds faster!!

    Of course, stepping back from premature nano-optimization, we see that the fastest that such a script with 100million returns could possibly run before optimizing is:

    sub nothing { return (); } nothing() for 0..100_000_000; warn time()-$^T;

    92 seconds. So our "10-times faster" has become "2% faster" and that is for a trivial and useless script. If your script actually did something useful, you'll almost certainly have something more like "0.02% faster". In other words, your benchmark is meaningless. Yes, meaningless.

    Pick between return (); vs. return; based on something other than speed. Both are of such trivial cost that the difference will never be noticed in any working code that does something useful or interesting.

    - tye        

    Updated: s/cmpthere/cmpthese/. Thanks, Limbic~Region.

      I agree with everything your say ;-) but I have a different slant on many of your points.

      Which shows why you should return undef;
      good point, yes that is a case when it would be use.

      have you heard of 'cmpthese' -- much better if you want to post your premature nano-optimization results
      yes I have, I just like the otherway more. Maybe one day I'll prefer the cmpthese() style.

      I also know that the benchmarks are, in pure real world terms, complete bullshit - but I wanted to know what the speed difference between return; and return() was, with no other considerations. That was the only reason for benchmarking them.

      The point was , if they bith give the same result in any context, when would you chose one over the other, though I agree it was misleading to say one was twice as fast - it could indicate I thought that was reason enough.

      How can you pass up the 10-times faster version that does return 0
      Easy, because in list context, it does not indicate failure - therefore in most cases, it is not what you want.

      Pick between return (); vs. return; based on something other than speed.
      I think that was my point - chose return() if it make your code clearer, otherwise always use return;

      +++++++++++++++++
      #!/usr/bin/perl
      use warnings;use strict;use brain;