Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

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

by !1 (Hermit)
on Dec 21, 2003 at 23:59 UTC ( #316274=note: print w/ replies, xml ) Need Help??


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

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


Comment on Re: Re: Re: Re: What should be returned in scalar context? (best practice)
Re: Re: Re: Re: Re: What should be returned in scalar context? (best practice)
by sauoq (Abbot) on Dec 22, 2003 at 02:23 UTC
    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

    Well, if the function returns an array reference in scalar context, the documentation should state that it "returns an array reference in scalar context." Simple as that. An "array" is not an "array reference" and to expect it to become one in scalar context is ridiculous.

    Just take these two functions:

    sub f1 { return my @x = (33, 42) } sub f2 { return (33, 42) }
    To document that the first returns a list and the second returns an array is perfectly acceptable (preferable, imho.) When you see f1() in the code, you know how it is going to act. Number of elements: my $nelts = f1(); ... First element: my ($first) = f1(); ... similarly, when you see f2() in the code, you can know how it will act. Last element: my $last = f2(); ... First element: my ($first) = f2(); (This is exactly why this discussion came up in the first place. Read the first node in this thread to orient yourself.)

    Juerd's mumblings (or ravings) about Perl builtins are quite irrelevant. Besides the fact that every single one of them is a special case, they aren't implemented in Perl to begin with; they are implemented in C.

    The phrase "returns an array" is a very nice way of explaining exactly what you mean without addressing every context separately. I won't avoid it.

    Update: Examples flipped. Thanks jarich for pointing that out. (I actually flipped my description, because I wanted to talk about list values first, and forgot to flip my examples.

    -sauoq
    "My two cents aren't worth a dime.";
    
      "returns an array" would be confusing to me, since it's not possible. Well, except maybe in an "lvalue" context.

      An array is a container, holding a list. You can't return containers. Only values. Scalar value is to scalar variable what list is to array. You can no more return a scalar variable than you can return an array.

      Put another way, you can't take a reference to a list, only to an array. And yet you can't take a reference to the return value of a subroutine. You have to construct an anonymous array (a new container) to hold the value.

      These are not just implementation issues. These are user-visible concepts, and affect your behavior if you have the proper model.

      Your casual conversation may make sense to you, but you'll confuse your reader. And the point of communication is to communicate for the reader, not just for your own notes.

      -- Randal L. Schwartz, Perl hacker
      Be sure to read my standard disclaimer if this is a reply.

        Your casual conversation may make sense to you, but you'll confuse your reader.

        My point is not a casual one even if my explanation has failed to be as clear as I would like. Allow me to try to explain it to you as it is fundamentally about documentation, and your skill at technical writing is unquestionable.

        When I document that a sub of mine "returns an array", I mean very specifically that the expression supplied to return() (be it explicit or implicit) is an array.

        My use of the word "return" corresponds directly to the Perl keyword "return" without trying to describe what return() itself actually does. This is a considered choice, not laziness or lack of understanding.

        The behavior of return() is not within my purview. Isn't it to my own benefit to avoid describing it? Don't I, in fact, have a responsibility to yield to its proper documentation?

        Granted this is unlikely, but for the sake of argument consider the possibility of return()'s behavior changing. Imagine that a boolean context and a couple boolean values are added to the language. (Yes, it is a ridiculous notion but bare with me.) By not attempting to enumerate every context in the first place, haven't I insulated my own documentation from the change and avoided the need for edits?

        I believe this to be a fine documentation strategy. It is simple and allows me to be brief, describe the code itself, and communicate exactly what to expect. It avoids redundancy and protects the documentation, the published interface, from outside changes. It ignores the sometimes sticky issue of context which, really, should not have to reappear in every function's documentation. For these reasons, I will continue to use it.

        The one concern that I do have is that it seems several people are confused by it. I find this disconcerting as it is really quite simple. My only explanation is that many people are either too focused on their knowledge of Perl's inner workings or are hung up on documenting their own functions like Perl builtins. (Builtins aren't coded in Perl and hence, it wouldn't make sense to refer to the return keyword in their documentation; this is true of XS code as well.) Whatever the case, this kind of confusion seems to be prevalent wherever lists and list context are discussed. Maybe people still aren't comfortable with the concepts and want to be reminded of the specifics at every turn.

        -sauoq
        "My two cents aren't worth a dime.";
        
      Now let me try this:

      sub f1 { return (33, 42) } sub f2 { return my @x = (33, 42) } my $nelts = f1(); # apparently returns number of elements (2) my ($first) = f1(); # apparently returns first element (33) my $last = f2(); # apparently returns last element (42) my ($first2) = f2(); # apparently returns first element (33) print "nelts: $nelts (expecting 2)\n"; print "first: $first (expecting 33)\n"; print "last: $last (expecing 42)\n"; print "first2: $first2 (expecting 33)\n";

      Let's run that shall we?

      # Output: nelts: 42 (expecting 2) first: 33 (expecting 33) last: 2 (expecing 42) first2: 33 (expecting 33)

      Hmm. So your suggestion that you can know how it will act isn't even quite true for yourself. But only because you got your examples backwards.

      It's interesting though, because I never really bothered noticing a different between the two return options. What you're saying is that if you give return an array then the returned value gives you the number of elements in the list when taken in scalar context. Whereas if you give return a list then the return value gives the final element of the list in scalar context.

      An unfortunate inconsistency and one which probably causes many subtle bugs.

      To document that the first returns a list and the second returns an array is perfectly acceptable

      I understand why you're arguing that there is a distinction between these two cases and I can guess why you feel its better to describe the second as returning an array. However I do agree that the statement is technically incorrect. The subroutine may be returning as an array but what you get back on the other side is a list until you copy it into an array. And you want it to be a list too, as there's very little value of even thinking of it being an array except for the fact that you can take it in scalar context to get the number of elements.

      Since the issue is on semantics and your attempt to denote a difference between the two ways of returning a list, I cannot recommend a better choice for how you should document this. I would say that the subroutine returns a list or the number of elements in that list in scalar context, rather than saying it returns an array. But I can understand, even if I don't agree, your reasons for your choice of words.

      I'm now going to have to take especial care in future, when calling subroutines which return lists in scalar context. Will I be getting the final value of the length of the list, because I suspect I usually assume the latter.

      jarich

        First, thanks for catching the fact that I had my examples switched. As I explain in my update, I edited my description and failed to switch my examples to match. Good catch and I appreciate your close attention.

        An unfortunate inconsistency and one which probably causes many subtle bugs.

        No, this is not an inconsistency. It is, in fact, consistent:

        $ perl -le 'print scalar(33, 42)' 42 $ perl -le 'print scalar(my @x = (33, 42))' 2
        It is well understood that list literals do not act like arrays in scalar context. The expression is evaluated in the proper context before it is returned.

        But I can understand, even if I don't agree, your reasons for your choice of words.

        I'm not sure you actually do, although you are making an effort to and I appreciate that. Let me see if I can better explain the point that others have so completely missed. When I say, "this sub returns an array," my meaning is very specific and clear. The sub explicitly or implicitly return()s an array. What return() does is already clearly documented in perldoc perlfunc and it is not my responsibility nor would it be prudent for me to duplicate that documentation.

        Let's say I document that the sub "returns a list or the number of elements in that list in scalar context" as you suggest. If the developers decide that return() should behave differently, my documentation may become incorrect. If I say simply that my function "returns an array" and a change is made to return()'s behavior, I don't need to change my documentation. It remains correct. Granted, the likelihood of return() changing is pretty much non-existent... but that's completely beside the point. My documentation methodology is perfectly sound.

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

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (7)
As of 2014-07-12 11:49 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    When choosing user names for websites, I prefer to use:








    Results (239 votes), past polls