Perl
  Home arrow Perl arrow Page 4 - Perl Subroutines: Arguments and Values
Dev Shed Forums  
Administration  
AJAX  
Apache  
BrainDump  
DHTML  
Flash  
Java  
JavaScript  
Multimedia  
MySQL  
Oracle  
Perl  
PHP  
Practices  
Python  
Reviews  
Security  
Smartphone Development  
Style-Sheets  
Web Services  
XML  
Zend  
Zope  
Mobile Linux  
App Generation ROI  
IBM® developerWorks  
Forums Sitemap  
E-Commerce Hosting  
Linux Web Hosting  
Managed Hosting  
Small Business Hosting  
VPS Hosting  
Weekly Newsletter

 
Developer Updates  
Free Website Content 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us Get Paid  
Request Media Kit
Contact Us  
Site Map  
Privacy Policy  
Support  
 USERNAME
 
 PASSWORD
 
 
  >>> SIGN UP!  
  Lost Password? 
Google.com  
PERL

Perl Subroutines: Arguments and Values
By: O'Reilly Media
  • Search For More Articles!
  • Disclaimer
  • Author Terms
  • Rating: starstarstarstarstar / 3
    2007-08-23


    Table of Contents:
  • Perl Subroutines: Arguments and Values
  • Default Argument Values
  • Scalar Return Values
  • Contextual Return Values

  • Rate this Article: Poor Best 
      ADD THIS ARTICLE TO:
      error-file:tidyout.log Del.ici.ous error-file:tidyout.log Digg
      error-file:tidyout.log Blink error-file:tidyout.log Simpy
      error-file:tidyout.log Google error-file:tidyout.log Spurl
      error-file:tidyout.log Y! MyWeb error-file:tidyout.log Furl
    Email Me Similar Content When Posted
    Add Developer Shed Article Feed To Your Site
    Email Article To Friend
    Print Version Of Article
    PDF Version Of Article

     
     
    ADVERTISEMENT


    Perl Subroutines: Arguments and Values - Contextual Return Values
    ( Page 4 of 4 )


    Make list-returning subroutines return the “obvious” value in scalar context.


    There is only one kind of list in Perl, so returning in a list context is easy—you just return all the values you produced:

      sub defined_samples_in {
          return grep {defined $_} @_;
      }

    But what should that subroutine return in a scalar context? It might legitimately return an integer count (like grep itself does), in which case the subroutine stays exactly the same:

      sub defined_samples_in {
          return grep {defined $_} @_;
      }

    Or it might instead return some serialized string representation of the list (like localtime does in scalar context):

      sub defined_samples_in {
          my @defined_samples = grep {defined $_} @_;

          # Return all defined args in list context...
         
    if (wantarray) {
              return @defined_samples;
          }
          # Otherwise a serialized version in scalar context...
         
    return join($COMMA, @defined_samples);
      }

    Or it might return the “next” value in a series (like readline does):

      use List::Util qw( first );

      sub defined_samples_in {
         
    # Return all defined args in list context...
         
    if (wantarray) {
              return grep {defined $_} @_;
          }

          # Or, in scalar context, extract the first defined arg...
         
    return first {defined $_} @_;
      }

    It might try to preserve as much information as possible and return the full list of values using an array reference (which no Perl 5 builtin does):

      sub defined_samples_in {
          my @defined_samples = grep {defined $_} @_;

          # Return all defined args in list context...
         
    if (wantarray) {
              return @defined_samples;
          }
         
    # Return all defined args (indirectly) in scalar context...
         
    return \@defined_samples;
      }

    It might even give up in disgust (like sort does):

      sub defined_samples_in {
          croak q{Useless use of 'defined_samples_in' in a non-list context}
              if !wantarray;

          return grep {defined $_} @_;
      }

    Perl’s list-returning builtins don’t have a consistent behaviour in scalar context. They try to “do the right thing” on a case-by-case basis. Mostly they get it right; the scalar context results of grep, and localtime, and readline are what most people expect them to be.

    Unfortunately, they don’t always get it right. The scalar return values of select , readpipe , splice , unpack , and the various get... functions can be surprising to infre quent users of these functions. They have to be either memorized or repeatedly looked up in the fine manual. For many people, this makes using those builtins harder than it should be.

    Don’t perpetuate those difficulties in your own development. If you’re writing a library of subroutines, make them predictable. Make every list-returning subroutine return the “obvious” value in scalar context.

    What’s the “obvious” value? It’s the value that the developers who use the subroutine actually expect it to return. For example, if they all use defined_samples_in() like so:

    defined_samples_in( ) like so: What’s the “obvious” value? It’s the value that the developers who use the subroutine actually expect it to return. For example, if they all use defined_samples_in( ) like so:

      if ( defined_samples_in(@samples) > 0 ) { 
         
    process(@samples);
      }

    then they obviously expect it to return a count of defined samples. So the “obvious” scalar context return value is that count.

    On the other hand, if everyone uses it like this:

      my $floor_samples_ref         = defined_samples_in(@floor_samples);
      my $restocked_samples_ref     = defined_samples_in(@restocked_samples);

      # and later...

      swap_arrays($floor_samples_ref, $restocked_samples_ref);

    then the expectation is clearly that the subroutine returns a reference to the array of results. So that’s the “obvious” scalar return value.

    In other words, the “obvious” return value in a scalar context is whatever the people who use your code think it’s going to be (before they read the fine manual). That definition of obviousness presents a dilemma, though. The way you work out whether your proposed scalar-context behaviour is obvious is by implementing it and seeing how many people it trips up. But once the subroutine is deployed and client code is relying on it, it’s too late to change its return value if that value turns out not to be what most people expect.

    The solution (which is discussed in greater detail in Chapter 17) is to “play test” the subroutine before it’s deployed. That is, ask the people who will actually be using your subroutine what they expect it will do in scalar context. Or, better yet, have them write sample code that uses the subroutine, and see how they use it. If you get a consensus (or even just a simple majority opinion), implement that. If you don’t get agreement on a single “obvious” behaviour, see the “Multi-Contextual Return Values” guideline later in this chapter.

    Unfortunately, getting this kind of preliminary feedback isn’t always feasible. In such cases, you should simply select a reasonable default, based on the three fundamental categories of list-returning subroutines: homogeneous, heterogeneous, and iterative.

    A homogeneous list-returning subroutine is one that returns a list of data values that are all of a single type: a list of samples, a list of names, or a list of images. Perl’s built-in map , grep , and sort are examples of this type of subroutine. Because no one value in a homogeneous list is more significant than any other, the only interesting property of the list in a scalar context is usually the number of values it contains. Hence, in scalar contexts, homogeneous subroutines are usually expected to return a count, as map and grep both do.

    A heterogeneous list-returning subroutine is one that returns a list containing distinct pieces of information: name, rank, and serial number; account number, account name, and balance; year, month, day. For example, the stat , caller , and getpwent builtins are all heterogeneous. The lists returned by subroutines of this type often do have a single piece of information that is more significant than any other, and they’re typically expected to return that value in scalar contexts. For example, caller returns the caller’s package name, whilst getpwent returns the relevant username.

    Alternatively, all of the information returned by a heterogeneous subroutine might be equally important. So this type of subroutine is sometimes expected to return some kind of serialized representation of that information in scalar context, as localtime and gmtime do.

    An iterative list-returning subroutine is one that returns an iterated series of values, typically the result of successive input operations. The builtins readline and readdir work this way. Iterative subroutines are always used for stepping through sequences of data, so in a scalar context, they should always return the result of a single iteration.

    Remember, though, that these suggested default behaviours are recommendations, not natural laws. You may find that your “play testing” suggests that some other return value is more appropriate—more expected—in your particular subroutine. In that case, you should implement and deploy that behaviour instead, and then explicitly document the reasons for your choice.

    Please check back next week for the conclusion to this article. 



     
     
    >>> More Perl Articles          >>> More By O'Reilly Media
     

       

    PERL ARTICLES

    - More Perl Bits
    - Perl, Bit by Bit
    - Basic Charting with Perl
    - Using Getopt::Long: More Command Line Option...
    - Command Line Options in Perl: Using Getopt::...
    - Web Access with LWP
    - More Templating Tools for Perl
    - Site Layout with Perl Templating Tools
    - Build a Perl RSS Aggregator with Templating ...
    - Looping, Security, and Templating Tools
    - Perl: Bon Voyage Lists and Hashes
    - Templating Tools
    - Perl: Number Crunching
    - Perl Debuggers in Detail
    - Debugging Perl





    © 2003-2009 by Developer Shed. All rights reserved. DS Cluster 2 Hosted by Hostway
    For more Enterprise Application Development news, visit eWeek