Programming Perl, Second Edition

Previous Chapter 1
An Overview of Perl
Next
 

1.5 Operators

As we alluded to earlier, Perl is also a mathematical language. This is true at several levels, from low-level bitwise logical operations, up through number and set manipulation, on up to larger predicates and abstractions of various sorts. And as we all know from studying math in school, mathematicians love strange symbols. What's worse, computer scientists have come up with their own versions of these strange symbols. Perl has a number of these strange symbols too, but take heart, most are borrowed directly from C, FORTRAN, sed (1) or awk (1), so they'll at least be familiar to users of those languages.

Perl's built-in operators may be classified by number of operands into unary, binary, and trinary operators. They may be classified by whether they're infix operators or prefix operators. They may also be classified by the kinds of objects they work with, such as numbers, strings, or files. Later, we'll give you a table of all the operators, but here are some to get you started.

Arithmetic Operators

Arithmetic operators do exactly what you would expect from learning them in school. They perform some sort of mathematical function on numbers.

Table 1.2: Some Binary Arithmetic Operators
Example Name Result
$a + $b Addition Sum of $a and $b
$a * $b Multiplication Product of $a and $b
$a % $b Modulus Remainder of $a divided by $b
$a ** $b Exponentiation $a to the power of $b

Yes, we left subtraction and division out of Table 1.2. But we suspect you can figure out how they should work. Try them and see if you're right. (Or cheat and look in the index.) Arithmetic operators are evaluated in the order your math teacher taught you (exponentiation before multiplication, and multiplication before addition). You can always use parentheses to make it come out differently.

String Operators

There is also an "addition" operator for strings that does concatenation. Unlike some languages that confuse this with numeric addition, Perl defines a separate operator (.) for string concatenation:

$a = 123;
$b = 456;
print $a + $b;     # prints 579
print $a . $b;     # prints 123456

There's also a "multiply" operation for strings, also called the repeat operator. Again, it's a separate operator (x) to keep it distinct from numeric multiplication:

$a = 123;
$b = 3;
print $a * $b;     # prints 369
print $a x $b;     # prints 123123123

These string operators bind as tightly as their corresponding arithmetic operators. The repeat operator is a bit unusual in taking a string for its left argument but a number for its right argument. Note also how Perl is automatically converting from numbers to strings. You could have put all the literal numbers above in quotes, and it would still have produced the same output. Internally though, it would have been converting in the opposite direction (that is, from strings to numbers).

A couple more things to think about. String concatenation is also implied by the interpolation that happens in double-quoted strings. When you print out a list of values, you're also effectively concatenating strings. So the following three statements produce the same output:

print $a . ' is equal to ' . $b . "\n";    # dot operator
print $a, ' is equal to ', $b, "\n";       # list
print "$a is equal to $b\n";               # interpolation

Which of these you use in any particular situation is entirely up to you.

The x operator may seem relatively worthless at first glance, but it is quite useful at times, especially for things like this:

print "-" x $scrwid, "\n";

which draws a line across your screen, presuming your screen width is in $scrwid.

Assignment Operators

Although it's not exactly a mathematical operator, we've already made extensive use of the simple assignment operator, =. Try to remember that = means "gets set to" rather than "equals". (There is also a mathematical equality operator == that means "equals", and if you start out thinking about the difference between them now, you'll save yourself a lot of headache later.)

Like the operators above, assignment operators are binary infix operators, which means they have an operand on either side of the operator. The right operand can be any expression you like, but the left operand must be a valid lvalue (which, when translated to English, means a valid storage location like a variable, or a location in an array). The most common assignment operator is simple assignment. It determines the value of the expression on its right side, and sets the variable on the left side to that value:

$a = $b;
$a = $b + 5;
$a = $a * 3;

Notice the last assignment refers to the same variable twice; once for the computation, once for the assignment. There's nothing wrong with that, but it's a common enough operation that there's a shortcut for it (borrowed from C). If you say:

lvalue operator= expression

it is evaluated as if it were:

lvalue = lvalue operator expression

except that the lvalue is not computed twice. (This only makes a difference if evaluation of the lvalue has side effects. But when it does make a difference, it usually does what you want. So don't sweat it.)

So, for example, you could write the above as:

$a *= 3;

which reads "multiply $a by 3". You can do this with almost any binary operator in Perl, even some that you can't do it with in C:

$line .= "\n";  # Append newline to $line.
$fill x= 80;    # Make string $fill into 80 repeats of itself.
$val ||= "2";   # Set $val to 2 if it isn't already set.

Line 6 of our grade example contains two string concatenations, one of which is an assignment operator. And line 14 contains a +=.

Regardless of which kind of assignment operator you use, the final value is returned as the value of the assignment as a whole. (This is unlike, say, Pascal, in which assignment is a statement and has no value.) This is why we could say:

chop($number = <STDIN>);

and have it chop the final value of $number. You also frequently see assignment as the condition of a while loop, as in line 4 of our grade example.

Autoincrement and Autodecrement Operators

As if $variable += 1 weren't short enough, Perl borrows from C an even shorter way to increment a variable. The autoincrement and autodecrement operators simply add (or subtract) one from the value of the variable. They can be placed on either side of the variable, depending on when you want them to be evaluated (see Table 1.3).

Table 1.3: Unary Arithmetic Operators
Example Name Result
+ +$a, $a+ + Autoincrement Add 1 to $a
- -$a, $a- - Autodecrement Subtract 1 from $a

If you place one of the auto operators before the variable, it is known as a pre-incremented (pre-decremented) variable. Its value will be changed before it is referenced. If it is placed after the variable, it is known as a post-incremented (post-decremented) variable and its value is changed after it is used. For example:

$a = 5;        # $a is assigned 5
$b = ++$a;     # $b is assigned the incremented value of $a, 6
$c = $a--;     # $c is assigned 6, then $a is decremented to 5

Line 15 of our grade example increments the number of scores by one, so that we'll know how many scores we're averaging the grade over. It uses a post-increment operator ($scores++), but in this case it doesn't matter, since the expression is in a void context, which is just a funny way of saying that the expression is being evaluated only for the side effect of incrementing the variable. The value returned is being thrown away.[21]

[21] The optimizer will notice this and optimize the post-increment into a pre-increment, because that's a little more efficient to execute. (You didn't need to know that, but we hoped it would cheer you up.)

Logical Operators

Logical operators, also known as "short-circuit" operators, allow the program to make decisions based on multiple criteria, without using nested conditionals. They are known as short-circuit because they skip evaluating their right argument if evaluating their left argument is sufficient to determine the overall value.

Perl actually has two sets of logical operators, a crufty old set borrowed from C, and a nifty new set of ultralow-precedence operators that parse more like people expect them to parse, and are also easier to read. (Once they're parsed, they behave identically though.) See Table 1.4 for examples of logical operators.

Table 1.4: Logical Operators
Example Name Result
$a && $b And

$a if $a is false, $b otherwise

$a || $b Or

$a if $a is true, $b otherwise

! $a Not True if $a is not true
$a and $b And

$a if $a is false, $b otherwise

$a or $b Or

$a if $a is true, $b otherwise

not $a Not True if $a is not true

Since the logical operators "short circuit" the way they do, they're often used to conditionally execute code. The following line (from our grade example) tries to open the file grades.

open(GRADES, "grades") or die "Can't open file grades: $!\n";

If it opens the file, it will jump to the next line of the program. If it can't open the file, it will provide us with an error message and then stop execution.

Literally, the above message means "Open grades or die!" Besides being another example of natural language, the short-circuit operators preserve the visual flow. Important actions are listed down the left side of the screen, and secondary actions are hidden off to the right. (The $! variable contains the error message returned by the operating system--see "Special Variables" in Chapter 2, The Gory Details). Of course, these logical operators can also be used within the more traditional kinds of conditional constructs, such as the if and while statements.

Comparison Operators

Comparison, or relational, operators tell us how two scalar values (numbers or strings) relate to each other. There are two sets of operators--one does numeric comparison and the other does string comparison. (In either case, the arguments will be "coerced" to have the appropriate type first.) Table 1.5 assumes $a and $b are the left and right arguments, respectively.

Table 1.5: Some Numeric and String Comparison Operators
Comparison Numeric String Return Value
Equal == eq True if $a is equal to $b
Not equal != ne True if $a is not equal to $b
Less than < lt True if $a is less than $b
Greater than > gt True if $a is greater than $b
Less than or equal <= le True if $a not greater than $b
Comparison <=> cmp 0 if equal, 1 if $a greater, -1 if $b greater

The last pair of operators (<=> and cmp) are entirely redundant. However, they're incredibly useful in sort subroutines (see Chapter 3, Functions).[22]

[22] Some folks feel that such redundancy is evil because it keeps a language from being minimalistic, or orthogonal. But Perl isn't an orthogonal language; it's a diagonal language. By which we mean that Perl doesn't force you to always go at right angles. Sometimes you just want to follow the hypotenuse of the triangle to get where you're going. TMTOWTDI is about shortcuts. Shortcuts are about efficiency.

File Test Operators

The file test operators allow you to test whether certain file attributes are set before you go and blindly muck about with the files. For example, it would be very nice to know that the file /etc/passwd already exists before you go and open it as a new file, wiping out everything that was in there before. See Table 1.6 for examples of file test operators.

Table 1.6: Some File Test Operators
Example Name Result
-e $a Exists True if file named in $a exists
-r $a Readable True if file named in $a is readable
-w $a Writable True if file named in $a is writable
-d $a Directory True if file named in $a is a directory
-f $a File True if file named in $a is a regular file
-T $a Text File True if file named in $a is a text file

Here are some examples:

-e "/usr/bin/perl" or warn "Perl is improperly installed\n";
-f "/vmunix" and print "Congrats, we seem to be running BSD Unix\n";

Note that a regular file is not the same thing as a text file. Binary files like /vmunix are regular files, but they aren't text files. Text files are the opposite of binary files, while regular files are the opposite of irregular files like directories and devices.

There are a lot of file test operators, many of which we didn't list. Most of the file tests are unary Boolean operators: they take only one operand, a scalar that evaluates to a file or a filehandle, and they return either a true or false value. A few of them return something fancier, like the file's size or age, but you can look those up when you need them.


Previous Home Next
Filehandles Book Index Control Structures

HTML: The Definitive Guide CGI Programming JavaScript: The Definitive Guide Programming Perl WebMaster in a Nutshell