the beginning or the end of the script. However, if you're using
lexically-scoped private variables created with my(), you'll have to make sure
your format or subroutine definition is within the same block scope
-as the my if you expect to to be able to access those private variables.
+as the my if you expect to be able to access those private variables.
Declaring a subroutine allows a subroutine name to be used as if it were a
list operator from that point forward in the program. You can declare a
-subroutine without defining it by saying just
+subroutine (prototyped to take one scalar parameter) without defining it by saying just:
- sub myname;
+ sub myname ($);
$me = myname $0 or die "can't get myname";
Note that it functions as a list operator though, not as a unary
side effects. Every simple statement must be terminated with a
semicolon, unless it is the final statement in a block, in which case
the semicolon is optional. (A semicolon is still encouraged there if the
-block takes up more than one line, since you may eventually add another line.)
+block takes up more than one line, because you may eventually add another line.)
Note that there are some operators like C<eval {}> and C<do {}> that look
like compound statements, but aren't (they're just TERMs in an expression),
and thus need an explicit termination if used as the last item in a statement.
} until $line eq ".\n";
See L<perlfunc/do>. Note also that the loop control
-statements described later will I<NOT> work in this construct, since
+statements described later will I<NOT> work in this construct, because
modifiers don't take loop labels. Sorry. You can always wrap
another block around it to do that sort of thing.
open(FOO) ? 'hi mom' : die "Can't open $FOO: $!";
# a bit exotic, that last one
-The C<if> statement is straightforward. Since BLOCKs are always
+The C<if> statement is straightforward. Because BLOCKs are always
bounded by curly brackets, there is never any ambiguity about which
C<if> an C<else> goes with. If you use C<unless> in place of C<if>,
the sense of the test is reversed.
# now process $line
}
-Or here's a a simpleminded Pascal comment stripper (warning: assumes no { or } in strings)
+Or here's a simpleminded Pascal comment stripper (warning: assumes no { or } in strings).
LINE: while (<STDIN>) {
while (s|({.*}.*){.*}|$1 |) {}
version 5, it has been deprecated, so please change any occurrences of "if BLOCK" to
"if (do BLOCK)".
-=head2 For and Foreach
+=head2 For Loops
-Perl's C-style C<for> loop works exactly like the corresponding C<while> loop:
+Perl's C-style C<for> loop works exactly like the corresponding C<while> loop;
+that means that this:
for ($i = 1; $i < 10; $i++) {
...
}
-is the same as
+is the same as this:
$i = 1;
while ($i < 10) {
$i++;
}
+(There is one minor difference: The first form implies a lexical scope
+for variables declared with C<my> in the initialization expression.)
+
+Besides the normal array index looping, C<for> can lend itself
+to many other interesting applications. Here's one that avoids the
+problem you get into if you explicitly test for end-of-file on
+an interactive file descriptor causing your program to appear to
+hang.
+
+ $on_a_tty = -t STDIN && -t STDOUT;
+ sub prompt { print "yes? " if $on_a_tty }
+ for ( prompt(); <STDIN>; prompt() ) {
+ # do something
+ }
+
+=head2 Foreach Loops
+
The C<foreach> loop iterates over a normal list value and sets the
-variable VAR to be each element of the list in turn. The variable is
-implicitly local to the loop and regains its former value upon exiting the
-loop. If the variable was previously declared with C<my>, it uses that
-variable instead of the global one, but it's still localized to the loop.
-This can cause problems if you have subroutine or format declarations
-within that block's scope.
+variable VAR to be each element of the list in turn. If the variable
+is preceded with the keyword C<my>, then it is lexically scoped, and
+is therefore visible only within the loop. Otherwise, the variable is
+implicitly local to the loop and regains its former value upon exiting
+the loop. If the variable was previously declared with C<my>, it uses
+that variable instead of the global one, but it's still localized to
+the loop. (Note that a lexically scoped variable can cause problems
+with you have subroutine or format declarations.)
The C<foreach> keyword is actually a synonym for the C<for> keyword, so
you can use C<foreach> for readability or C<for> for brevity. If VAR is
for (@ary) { s/foo/bar/ }
- foreach $elem (@elements) {
+ foreach my $elem (@elements) {
$elem *= 2;
}
Here's how a C programmer might code up a particular algorithm in Perl:
- for ($i = 0; $i < @ary1; $i++) {
- for ($j = 0; $j < @ary2; $j++) {
+ for (my $i = 0; $i < @ary1; $i++) {
+ for (my $j = 0; $j < @ary2; $j++) {
if ($ary1[$i] > $ary2[$j]) {
last; # can't go to outer :-(
}
$ary1[$i] += $ary2[$j];
}
+ # this is where that last takes me
}
-Whereas here's how a Perl programmer more confortable with the idiom might
-do it this way:
+Whereas here's how a Perl programmer more comfortable with the idiom might
+do it:
- OUTER: foreach $i (@ary1) {
- INNER: foreach $j (@ary2) {
- next OUTER if $i > $j;
- $i += $j;
+ OUTER: foreach my $wid (@ary1) {
+ INNER: foreach my $jet (@ary2) {
+ next OUTER if $wid > $jet;
+ $wid += $jet;
}
}
-See how much easier this is? It's cleaner, safer, and faster.
-It's cleaner because it's less noisy.
-It's safer because if code gets added
-between the inner and outer loops later, you won't accidentally excecute
-it because you've explicitly asked to iterate the other loop rather than
-merely terminating the inner one.
-And it's faster because Perl exececute C<foreach> statement more
-rapidly than it would the equivalent C<for> loop.
+See how much easier this is? It's cleaner, safer, and faster. It's
+cleaner because it's less noisy. It's safer because if code gets added
+between the inner and outer loops later on, the new code won't be
+accidentally executed. The C<next> explicitly iterates the other loop
+rather than merely terminating the inner one. And it's faster because
+Perl executes a C<foreach> statement more rapidly than it would the
+equivalent C<for> loop.
=head2 Basic BLOCKs and Switch Statements
-A BLOCK by itself (labeled or not) is semantically equivalent to a loop
-that executes once. Thus you can use any of the loop control
-statements in it to leave or restart the block. The C<continue> block
-is optional.
+A BLOCK by itself (labeled or not) is semantically equivalent to a
+loop that executes once. Thus you can use any of the loop control
+statements in it to leave or restart the block. (Note that this is
+I<NOT> true in C<eval{}>, C<sub{}>, or contrary to popular belief
+C<do{}> blocks, which do I<NOT> count as loops.) The C<continue>
+block is optional.
The BLOCK construct is particularly nice for doing case
structures.
$nothing = 1;
}
-(That's actually not as strange as it looks one you realize that you can
+(That's actually not as strange as it looks once you realize that you can
use loop control "operators" within an expression, That's just the normal
C comma operator.)
die "unknown value for form variable where: `$where'";
}
+Another interesting approach to a switch statement is arrange
+for a C<do> block to return the proper value:
+
+ $amode = do {
+ if ($flag & O_RDONLY) { "r" }
+ elsif ($flag & O_WRONLY) { ($flag & O_APPEND) ? "a" : "w" }
+ elsif ($flag & O_RDWR) {
+ if ($flag & O_CREAT) { "w+" }
+ else { ($flag & O_APPEND) ? "a+" : "r+" }
+ }
+ };
+
=head2 Goto
Although not for the faint of heart, Perl does support a C<goto> statement.
propagated to the other subroutine.) After the C<goto>, not even caller()
will be able to tell that this routine was called first.
-In almost cases like this, it's usually a far, far better idea to use the
-structured control flow mechanisms of C<next>, C<last>, or C<redo> insetad
+In almost all cases like this, it's usually a far, far better idea to use the
+structured control flow mechanisms of C<next>, C<last>, or C<redo> instead of
resorting to a C<goto>. For certain applications, the catch and throw pair of
C<eval{}> and die() for exception processing can also be a prudent approach.
+
+=head2 PODs: Embedded Documentation
+
+Perl has a mechanism for intermixing documentation with source code.
+While it's expecting the beginning of a new statement, if the compiler
+encounters a line that begins with an equal sign and a word, like this
+
+ =head1 Here There Be Pods!
+
+Then that text and all remaining text up through and including a line
+beginning with C<=cut> will be ignored. The format of the intervening
+text is described in L<perlpod>.
+
+This allows you to intermix your source code
+and your documentation text freely, as in
+
+ =item snazzle($)
+
+ The snazzle() function will behave in the most spectacular
+ form that you can possibly imagine, not even excepting
+ cybernetic pyrotechnics.
+
+ =cut back to the compiler, nuff of this pod stuff!
+
+ sub snazzle($) {
+ my $thingie = shift;
+ .........
+ }
+
+Note that pod translators should look at only paragraphs beginning
+with a pod directive (it makes parsing easier), whereas the compiler
+actually knows to look for pod escapes even in the middle of a
+paragraph. This means that the following secret stuff will be
+ignored by both the compiler and the translators.
+
+ $a=3;
+ =secret stuff
+ warn "Neither POD nor CODE!?"
+ =cut back
+ print "got $a\n";
+
+You probably shouldn't rely upon the warn() being podded out forever.
+Not all pod translators are well-behaved in this regard, and perhaps
+the compiler will become pickier.