Book HomeLearning Perl, 3rd EditionSearch this book

10.3. Expression Modifiers

In order to have a more compact notation, an expression may be followed by a modifier that controls it. For example, the if modifier works in a way analogous to an if block:

print "$n is a negative number.\n" if $n < 0;

That gives exactly the same result as if we had used this code, except that we saved some typing by leaving out the parentheses and curly braces:[216]

[216]We also left out the line breaks. But we should mention that the curly-brace form does create a new scope. In the rare case that you need the full details, check the documentation.

if ($n < 0) {
  print "$n is a negative number.\n";
}

As we've said, Perl folks generally like to avoid typing. And the shorter form reads like in English: print this message, if $n is less than zero.

Notice that the conditional expression is still evaluated first, even though it's written at the end. This is backwards from the usual left-to-right ordering; in understanding Perl code, we'll have to do as Perl's internal compiler does, and read to the end of the statement before we can tell what it's really doing.

There are other modifiers as well:

&error("Invalid input") unless &valid($input);
$i *= 2 until $i > $j;
print " ", ($n += 2) while $n < 10;
&greet($_) foreach @person;

These all work just as (we hope) you would expect. That is, each one could be rewritten in a similar way to rewriting the if-modifier example earlier. Here is one:

while ($n < 10) {
  print " ", ($n += 2);
}

The expression in parentheses inside the print argument list is noteworthy because it adds two to $n, storing the result back into $n. Then it returns that new value, which will be printed.

These shorter forms read almost like a natural language: call the &greet subroutine for each @person in the list. Double $i until it's larger than $j.[217]

[217]Well, it helps us to think of them like that.

One of the common uses of these modifiers is in a statement like this one:

print "fred is '$fred', barney is '$barney'\n"           if $I_am_curious;

By writing the code "in reverse" like this, you can put the important part of the statement at the beginning. The point of that statement is to monitor some variables; the point is not to check whether you're curious.[218] Some people prefer to write the whole statement on one line, perhaps with some tab characters before the if, to move it over toward the right margin, as we showed in the previous example, while others put the if modifier indented on a new line:

[218]Of course, we made up the name $I_am_curious; it's not a builtin Perl variable. Generally, folks who use this technique will either call their variable $TRACING, or will use a constant declared with the constant pragma.

print "fred is '$fred', barney is '$barney'\n"
    if $I_am_curious;

Although you can rewrite any of these expressions with modifiers as a block (the "old-fashioned" way), the converse isn't necessarily true. Only a single expression is allowed on either side of the modifier. So you can't write something if something while something until something unless something foreach something, which would just be too confusing. And you can't put multiple statements on the left of the modifier. If you need more than just a simple expression on each side, just write the code the old-fashioned way, with the parentheses and curly braces.

As we mentioned in relation to the if modifier, the control expression (on the right) is always evaluated first, just as it would be in the old-fashioned form.

With the foreach modifier, there's no way to choose a different control variable -- it's always $_. Usually, that's no problem, but if you want to use a different variable, you'll need to rewrite it as a traditional foreach loop.



Library Navigation Links

Copyright © 2002 O'Reilly & Associates. All rights reserved.