in reply to Re: (jeffa) Re: How to open sub FH when filename is passed to sub?
in thread How to open sub FH when filename is passed to sub?

You are most welcome. Yes, that is exactly why i use shift. shift returns the first value from an array, in this case it is the implied array @_ which is used by Perl to store the arguments passed to a given subroutine. I could have used this instead:
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;
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:
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; }
are three different functions with the same name. Perl chose instead to pass arguments in a list named @_. This is more flexible:
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";
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:

(subroutine lifted from python.org)

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?')
But with our own Ovid's Sub::NamedParams, we can do the same in Perl:
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?'}); }
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 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?'); }
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).

(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)