Most (if not all...) other languages use an argument list to specify what a subroutine can be 'passed', as well as a return type (together these form the 'signature'). For example, in Java, these:my $filename = shift @_; # or even my ($filename) = @_; # multiple arguments are best caught this way: my ($first,$second,$third) = @_; # but some folks prefer my $first = shift; my $second = shift; my $third = shift;
are three different functions with the same name. Perl chose instead to pass arguments in a list named @_. This is more flexible:public static void do_something(String str) { System.out.println("got " + str); } public static void do_something(String str, int numb) { System.out.println("got " + str); System.out.println("got " + numb); } public static int do_something() { return 42; }
How's that for flexibility! ;) Of course, with great power comes great responsibilty, and it is very easy to 'shoot your foot'. Some folks curse Perl for this power. The Python folks decided to allow named args, like so:sub do_it { my ($str,$numb) = @_; print "got $str\n" if $str; print "got $numb\n" if $numb; return 42; } # and you call it like so: do_it('Hello World'); do_it('lucky number',7); print "the answer is ", do_it(), "\n";
(subroutine lifted from python.org)
But with our own Ovid's Sub::NamedParams, we can do the same in Perl:def ask_ok(prompt, retries=4, complaint='Yes or no, please!'): while 1: ok = raw_input(prompt) if ok in ('y', 'ye', 'yes'): return 1 if ok in ('n', 'no', 'nop', 'nope'): return 0 retries = retries - 1 if retries < 0: raise IOError, 'refusenik user' print complaint quit = 0 while not quit: quit = ask_ok(prompt = 'Do you really want to quit?')
There is more than one way to do it. stephen wrote Attribute::Default to handle the same problem. The trick to this module is that you have to subclass the package - but who says main can't be a subclass? Named arguments are accessed through a hash:use strict; use Sub::NamedParams qw(wrap); wrap( 'sub' => 'ask_ok', names => [qw(prompt retries complaint)], hashref => 1, default => { prompt => 'Enter answer:', retries => 4, complaint => 'Yes or no, please!', } ); sub ask_ok { my ($prompt,$retries,$complaint) = @_; { print $prompt; chomp (my $answer = <>); return 1 if $answer =~ /y\b|ye\b|yes\b/; return 0 if $answer =~ /n\b|no\b|nop\b|nope\b/; $retries--; die 'refusenik user' if $retries < 0; print "$complaint\n"; redo } } my $quit; while (not $quit) { $quit = ask_ok({prompt => 'Do you really want to quit?'}); }
Both of these require a bit more work than Python - but remember that this functionality was not built into Perl 5 and Python 2 had the advantage of coming out after (but i still think named and default args a bit overrated, personally). Perl 6 will remedy this (thanks for the confirm Elian).use strict; use base qw(Attribute::Default); sub ask_ok : Default({ prompt=>'', retries=>4, complaint=>'Yes or no, +please!' }) { my %arg = @_; { print $arg{prompt}; chomp (my $answer = <>); return 1 if $answer =~ /y\b|ye\b|yes\b/; return 0 if $answer =~ /n\b|no\b|nop\b|nope\b/; $arg{retries}--; die 'refusenik user' if $arg{retries} < 0; print $arg{complaint}, "\n"; redo } } my $quit; while (not $quit) { $quit = ask_ok(prompt => 'Do you really want to quit?'); }
(thanks to chromatic for catching a silly error)
jeffa
L-LL-L--L-LL-L--L-LL-L-- -R--R-RR-R--R-RR-R--R-RR B--B--B--B--B--B--B--B-- H---H---H---H---H---H--- (the triplet paradiddle with high-hat)
In reply to More than you ever wanted to know about shift @_
by jeffa
in thread How to open sub FH when filename is passed to sub?
by Anonymous Monk
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |