Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

Re: What should be returned in scalar context? (best practice)

by sauoq (Abbot)
on Dec 03, 2003 at 00:15 UTC ( [id://311792]=note: print w/replies, xml ) Need Help??


in reply to What should be returned in scalar context?

Expectations should be defined by the language, not the programmer. Therefore, I think we should standardize on... well, nothing. Because Perl doesn't. I do, however, believe there is a best practice: unless you have a very good reason, it is best to sidestep the issue entirely and let Perl provide behavior that is already familiar to the programmer.

It is easy to imagine a function where it makes the most sense to return a reference to an array in scalar context. Likewise, it is easy to imagine one where it makes the most sense to return a formatted string. Neither would make sense as a default though. They are special cases.

In fact, the only time you should be mucking around with the return value in different contexts is when you have a special case. (And it just so happens that many, if not most, of Perl's builtins are sensibly treated as special cases.)

The right "default" behavior, in my opinion, is to return @ret; and let the programmer using your function sort it out. Document that your function returns an array and be done with it. Perl does a fine job of defining expectations for arrays, and your function can rely on those...

my $nelts = @array; # Number of elements. my ($first) = @array; # First element. my @whole = @array; # Whole thing. sub some_func { return @array } my $nelts = some_func(); # Number of elements. my ($first) = some_func(); # First element. my @whole = some_func(); # Whole thing.
That's about as consistent as it gets in Perl. It'll serve you well too, should you need to globally replace an array with a function call or vice-versa.

I think that returning a list literal (such as you create with the slice @ret[0 .. $#ret] in your example) is sorta-semi-okay as an alternative, but probably not nearly as useful. It also isn't very common practice and should probably be much more carefully documented when used. Still, I suppose Perl provides the right expectations insofar as $x = qw( a b c ); and sub f { qw(a b c) }; $x = f(); both set $x equal to 'c'.

Out of all of your examples, the one that makes me cringe is your "something completely different" example. Why go to the trouble ensuring my $i = foo(); is equivalent to my ($i) = foo(); when most perl programmers have already gone to the trouble to learn that they probably aren't? It hardly seems worth the obfuscation. I expect most, if they ran across that function, would spend much longer trying to figure out exactly why you did it that way than they ever would working out a bug caused by calling it in scalar context. I include myself in that.

-sauoq
"My two cents aren't worth a dime.";

Replies are listed 'Best First'.
Re: Re: What should be returned in scalar context? (best practice)
by Juerd (Abbot) on Dec 21, 2003 at 17:13 UTC

    The right "default" behavior, in my opinion, is to return @ret; and let the programmer using your function sort it out. Document that your function returns an array and be done with it.

    No, please don't!

    Document that it returns a list. It's not possible to return an array. It is possible to return an array reference, but this code is not doing that. If you document that some functions returns an array, the user can only guess: is it a list or an array reference?

    Document that your function returns a list and be done with it.

    Juerd # { site => 'juerd.nl', plp_site => 'plp.juerd.nl', do_not_use => 'spamtrap' }

      But if you say return @ret you aren't returning a list when called in scalar context. You have to say return @ret[0..$#ret] for that.

        But if you say return @ret you aren't returning a list when called in scalar context.

        While that is true, it is *never* returning an array in any context. At least when you say list, that's some indication you should use the sub in list context :)

        Juerd # { site => 'juerd.nl', plp_site => 'plp.juerd.nl', do_not_use => 'spamtrap' }

        Seven years later I come to this thread and wonder why what you said here got no real attention.

        And seven years later, I still agree with (nearly) everything I myself said in this thread.

        Pedantry be damned. It's nice enough ammo for meaningless flame wars on sites like this one but when people are actually working together on a common goal and not pulling out their micrometers for a geek pecker measuring contest, I've learned that many of them are too smart to bother being pedantic.

        Thank heavens for that.

        Anyway, I'm still saying "returns an array" and everything is moving along as smooth as I might hope. Turns out that telling people what I am doing works just fine. (They've already learned what Perl does.)

        And here was the crux of it all along. When I return an array (sub foo { @a = qw/2 4 6 8/ }) it simply doesn't behave the same as when I return a list (sub bar { qw/2 4 6 8/ }). Go figure. And with my convenient shorthand, I don't have to explain about this context or that one and get into petty details unless I'm doing something strange. Like using wantarray.

        Makes you wonder if Perl was slapped together by a some crazy linguist or something.

        -sauoq
        "My two cents aren't worth a dime.";
      Document that it returns a list. It's not possible to return an array.

      No. I would (will and do) document that it returns an array. What you are saying might be true from an internals standpoint, but that's irrelevant. Read the code: return @ret; . . . it says "return" and is followed by an array. More importantly, it behaves like an array. It doesn't behave like a list literal (a slice does, however, as ysth points out.) It certainly doesn't behave like an array reference. Documenting that it returns an array is the only clear way to describe its behavior.

      If you document that some functions returns an array, the user can only guess: is it a list or an array reference?

      When a funtion returns an array reference, document that it returns an array reference. "Array" and "array reference" are not synonyms. The user doesn't have to guess! He just has to read.

      If you sometimes describe a reference to an array as "an array", then you are being sloppy and you should stop.

      -sauoq
      "My two cents aren't worth a dime.";
      

        Read the code: return @ret; . . . it says "return" and is followed by an array.

        print @foo; does not print an array, it prints a list.

        More importantly, it behaves like an array.

        Only in two ways. It returns a number of elements in scalar context and a list of elements in list context. That's where the comparison ends.

        You can't splice what your function returns, push onto it, shift from it, unshift onto it, pop from it, reference it as an array, tie it, assign to it or undef it.

        It is not an array. Don't call it an array, because it simply is not an array. You say it behaves like an array, but it does not. The very things that make an array an array do not apply. Just some context sensitivity, but that does not make your list or number an array.

        If you don't want to call it a list because in scalar context it returns a number of elements, specify both behaviours in your documentation. That's what perl's documentation also does. See grep, keys, split, etcetera.

        "Returns a list" is wrong when the sub is called in scalar context. "Returns an array" is wrong in every possible context. Note that "array context" does exist and your sub cannot be used in it.

        Only an lvalue sub can return an array, but that cannot be done using the return keyword.

        It doesn't behave like a list literal

        Indeed. It does not behave like a list *literal*. But in list context, it does behave like a list, in every single way. It's important to know that there are two kinds of lists, and that list literals are special with syntax; other than that, they're just lists.

        Documenting that it returns an array is the only clear way to describe its behavior.

        No, no, no, no, NO! It's the most vague way to describe its behaviour. Don't call it clear, because it is the very opposite of clear! If you want to be absolutely clear, you must specify the difference in behaviour for every context, or modify the sub so that it really does behave like an array, or like a list.

        "Array" and "array reference" are not synonyms.

        Correct. But why do you think that "list" and "array" are synonyms? They're not. My point is not that "returns an array" would imply it being a reference. My point is that it's entirely unclear whether it returns a list or a reference to an array. It's not returning an array, that's for sure (since you use the return keyword, we're not talking about an lvalue sub here).

        If you sometimes describe a reference to an array as "an array", then you are being sloppy and you should stop.

        I could not agree more.

        I'd like to add this one:
        If you sometimes describe a list as "an array", then you are being sloppy and you should stop.

        Juerd # { site => 'juerd.nl', plp_site => 'plp.juerd.nl', do_not_use => 'spamtrap' }

        I would (will and do) document that it returns an array...When a funtion returns an array reference, document that it returns an array reference.

        Ummm. Perhaps it just has to do with the way I've been taught to document my code but documenting that a subroutine returns an array is very ambiguous especially considering the fact that you can have a subroutine detect context and return the contents of the array for list context and an arrayref in scalar context (this is the behavior I actually expect when the documentation says array because part of my job involves using mod_perl where you need to watch memory consumption). Of course, you could also have it return the number of elements in scalar context. However, just saying that it returns an array can most certainly be a cause for confusion. Since the purpose of documentation is to make certain that the reader clearly understands how to use your module, avoid using "returns an array".

        A reply falls below the community's threshold of quality. You may see it by logging in.
Re: Re: What should be returned in scalar context? (best practice)
by graff (Chancellor) on Dec 08, 2003 at 06:01 UTC
    Yes. Yes! If there is a "right" answer to tilly's question, it seems to me like this is it -- given that he was asking what should be the default behavior.

    I ++'d a lot of nodes on this thread, but I wish I could "+=3" on this one by sauoq.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://311792]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (6)
As of 2024-04-16 12:11 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found