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.

The rest of you can take comfort in knowing that, by learning all these strange symbols in Perl, you've given yourself a head start on all those other strange languages.

Perl's built-in operators may be classified by number of operands into unary, binary, and trinary (or ternary) operators. They may be classified by whether they're prefix operators (which go in front of their operands) or infix operators (which go in between their operands). 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 first here are some handy ones to get you started.

Some Binary Arithmetic Operators

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

ExampleNameResult
$a + $bAdditionSum of $a and $b
$a * $bMultiplicationProduct of $a and $b
$a % $bModulusRemainder of $a divided by $b
$a ** $bExponentiation$a to the power of $b

Yes, we left out subtraction and division—we suspect you can figure out how they should work. Try them and see if you're right. (Or cheat and look in Chapter 3.) Arithmetic operators are evaluated in the order your math teacher taught you (exponentiation before multiplication; 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 performs concatenation (that is, joining strings end to end). 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" operator for strings, 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. And 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. (But bear in mind that interpolation is often the most readable.)

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 $scrwid contains your screen width, and not your screw identifier.

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. The == operator is like a function that returns a Boolean value, while = is more like a procedure that is evaluated for the side effect of modifying a variable.)

Like the operators described earlier, 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 then 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 previous example 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 "true".

Line 6 of our Average Example[16] 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 of the variable on the left is returned as the value of the assignment as a whole.[17] This will not surprise C programmers, who will already know how to use this idiom to zero out variables:

$a = $b = $c = 0;

You'll also frequently see assignment used as the condition of a while loop, as in line 4 of our average example.

What will surprise C programmers is that assignment in Perl returns the actual variable as an lvalue, so that you can modify the same variable more than once in a statement. For instance, you could say:

($temp -= 32) *= 5/9;

to do an in-place conversion from Fahrenheit to Celsius. This is also why earlier in this chapter we could say:

chop($number = <STDIN>);

and have it chop the final value of $number. Generally speaking, you can use this feature whenever you want to copy something and at the same time do something else with it.

Unary Arithmetic 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:

ExampleNameResult
++$a, $a++AutoincrementAdd 1 to $a
--$a, $a--AutodecrementSubtract 1 from $a

If you place one of these "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 Average Example increments the number of scores by one, so that we'll know how many scores we're averaging. 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.[18]

Logical Operators

Logical operators, also known as "short-circuit" operators, allow the program to make decisions based on multiple criteria without using nested if statements. They are known as short-circuit operators because they skip (short circuit) the evaluation of their right argument if they decide the left argument has already supplied enough information to decide the overall value. This is not just for efficiency. You are explicitly allowed to depend on this short-circuiting behavior to avoid evaluating code in the right argument that you know would blow up if the left argument were not "guarding" it. You can say "California or bust!" in Perl without busting (presuming you do get to California).

Perl actually has two sets of logical operators, a traditional set borrowed from C and a newer (but even more traditional) set of ultralow-precedence operators borrowed from BASIC. Both sets contribute to readability when used appropriately. C's punctuational operators work well when you want your logical operators to bind more tightly than commas, while BASIC's word-based operators work well when you want your commas to bind more tightly than your logical operators. Often they work the same, and which set you use is a matter of personal preference. (For contrastive examples, see Section 3.20 in Chapter 3.) Although the two sets of operators are not interchangeable due to precedence, once they're parsed, the operators themselves behave identically; precedence merely governs the extent of their arguments. Table 1.1 lists logical operators.

Table 1-1. Logical Operators

ExampleNameResult
$a && $bAnd$a if $a is false, $b otherwise
$a || $bOr$a if $a is true, $b otherwise
! $aNotTrue if $a is not true
   
$a and $bAnd$a if $a is false, $b otherwise
$a or $bOr$a if $a is true, $b otherwise
not $aNotTrue if $a is not true
$a xor $bXorTrue if $a or $b is true, but not both

Since the logical operators "short-circuit" the way they do, they're often used in Perl to conditionally execute code. The following line (line 3 from our Average 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, this line means "Open grades or bust!" 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 Chapter 28.) Of course, these logical operators can also be used within the more traditional kinds of conditional constructs, such as the if and while statements.

Some Numeric and String 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.) Assuming left and right arguments of $a and $b, we have:

ComparisonNumericStringReturn Value
Equal==eqTrue if $a is equal to $b
Not equal!=neTrue if $a is not equal to $b
Less than<ltTrue if $a is less than $b
Greater than>gtTrue if $a is greater than $b
Less than or equal<=leTrue if $a not greater than $b
Greater than or equal>=geTrue if $a not less than $b
Comparison<=>cmp0 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 29).[19]

Some 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. The most basic file attribute is, of course, whether the file exists. For example, it would be very nice to know whether your mail aliases file already exists before you go and open it as a new file, wiping out everything that was in there before. Here are a few of the file test operators:

ExampleNameResult
-e $aExistsTrue if file named in $a exists
-r $aReadableTrue if file named in $a is readable
-w $aWritableTrue if file named in $a is writable
-d $aDirectoryTrue if file named in $a is a directory
-f $aFileTrue if file named in $a is a regular file
-T $aText FileTrue if file named in $a is a text file

You might use them like this:

-e "/usr/bin/perl" or warn "Perl is improperly installed\n";
-f "/vmlinuz" and print "I see you are a friend of Linus\n";

Note that a regular file is not the same thing as a text file. Binary files like /vmlinuz 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, which is to say they take only one operand (a scalar that evaluates to a filename 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 in the Section 3.10 in Chapter 3.



[16] Thought we'd forgotten it, didn't you?

[17] This is unlike, say, Pascal, in which assignment is a statement and returns no value. We said earlier that assignment is like a procedure, but remember that in Perl, even procedures return values.

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

[19] 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 this 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.

Get Programming Perl, 3rd Edition now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.