Item 25: Use wantarray to write subroutines returning lists.


Item 25: Use wantarray to write subroutines returning lists.

You probably already know that subroutines can return either scalar or list values. Perhaps you have written both kinds of subroutine. You also probably understand the significance of scalar and list context in Perl. In an idle moment, you may have even wondered how something like the following worked:

Create a sorted list of text files in a directory.

 sub sorted_text_files {    local *DIRH;    my $dir = shift;    opendir DIRH, $dir or die "eh?: $!";    @files = grep { -T }        map { "$dir/$_" } readdir DIRH;    sort @files;  } 

Localize the dirhandle.

It's not relevant to wantarray , but note that we have to add the dir prefix to make this work.

If you write something like:

 print join " ", sorted_text_files "/etc"; 

then you get the expected list of files. Because it's what you expect, you probably don't see anything magical about it. However, things are different if you instead write:

 print join " ", scalar(sorted_text_files "/etc"); 

In this case, you get no output .

Maybe what's going will become more apparent if you change the last line, sort @files , to read @files = sort @files . Now, instead of nothing at all, you get a number. Hmm.

What you are seeing is the result of the way that Perl evaluates the return value of a subroutine. The contextlist or scalarof the return value of a subroutine is determined by the context in which the subroutine is called . The context is noted when the subroutine is called, and that context is applied to whatever expression winds up as the return value. [5] If you need to know what the calling context is, you can use the wantarray operator, which returns true if the subroutine call appeared in a list context. Let's say that you want to modify the sorted_text_files subroutine so that it returns a join -ed list of filenames if evaluated in a scalar context. You could rewrite it like this:

[5] You probably shouldn't think too hard about how Perl's "last expression evaluated" return mechanism works, especially in conjunction with the calling context. Some things, like why we have bilateral symmetry, or whether you should inhale or exhale on your golf backswing, are better left to the philosophers . But as I said earlier, you do get the source code.

Create a sorted list of text files in a directory (improved version).

 sub sorted_text_files {    local *DIRH;    my $dir = shift;    opendir DIRH, $dir or die "eh?: $!"; 

Localize the dirhandle.

 @files = grep { -T }        map { "$dir/$_" } readdir DIRH;    if (wantarray) {      sort @files;    } else {      join " ", sort @files;    }  } 

List or scalar context?

List: return a list.

Scalar: return a string.

The wantarray operator is also occasionally useful for answering questions. When I was writing the Idiomatic Perl section and wanted to find out whether grep 's block argument was evaluated in a scalar or list context, I wrote something like the following:

 sub how { print wantarray ? "arrayish" : "scalarish" }  grep { how() } 1; 

If you run this, it produces the output:

 scalarish 

which pretty much settles the question.



Effective Perl Programming. Writing Better Programs with Perl
Effective Perl Programming: Writing Better Programs with Perl
ISBN: 0201419750
EAN: 2147483647
Year: 1996
Pages: 116

Similar book on Amazon

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net